44f0cf51cd0f130bb201741375f10b1117178517
[platform/upstream/weston.git] / libweston / 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 is hereby granted, free of charge, to any person obtaining
8  * a copy of this software and associated documentation files (the
9  * "Software"), to deal in the Software without restriction, including
10  * without limitation the rights to use, copy, modify, merge, publish,
11  * distribute, sublicense, and/or sell copies of the Software, and to
12  * permit persons to whom the Software is furnished to do so, subject to
13  * the following conditions:
14  *
15  * The above copyright notice and this permission notice (including the
16  * next paragraph) shall be included in all copies or substantial
17  * portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
23  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
24  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26  * SOFTWARE.
27  */
28
29 #include "config.h"
30
31 #include <errno.h>
32 #include <stdlib.h>
33 #include <stdint.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <math.h>
37 #include <sys/mman.h>
38 #include <sys/types.h>
39 #include <fcntl.h>
40 #include <unistd.h>
41 #include <linux/fb.h>
42 #include <linux/input.h>
43
44 #include <libudev.h>
45
46 #include "shared/helpers.h"
47 #include "compositor.h"
48 #include "compositor-fbdev.h"
49 #include "launcher-util.h"
50 #include "pixman-renderer.h"
51 #include "libinput-seat.h"
52 #include "presentation-time-server-protocol.h"
53
54 struct fbdev_backend {
55         struct weston_backend base;
56         struct weston_compositor *compositor;
57         uint32_t prev_state;
58
59         struct udev *udev;
60         struct udev_input input;
61         uint32_t output_transform;
62         struct wl_listener session_listener;
63 };
64
65 struct fbdev_screeninfo {
66         unsigned int x_resolution; /* pixels, visible area */
67         unsigned int y_resolution; /* pixels, visible area */
68         unsigned int width_mm; /* visible screen width in mm */
69         unsigned int height_mm; /* visible screen height in mm */
70         unsigned int bits_per_pixel;
71
72         size_t buffer_length; /* length of frame buffer memory in bytes */
73         size_t line_length; /* length of a line in bytes */
74         char id[16]; /* screen identifier */
75
76         pixman_format_code_t pixel_format; /* frame buffer pixel format */
77         unsigned int refresh_rate; /* Hertz */
78 };
79
80 struct fbdev_output {
81         struct fbdev_backend *backend;
82         struct weston_output base;
83
84         struct weston_mode mode;
85         struct wl_event_source *finish_frame_timer;
86
87         /* Frame buffer details. */
88         char *device;
89         struct fbdev_screeninfo fb_info;
90         void *fb; /* length is fb_info.buffer_length */
91
92         /* pixman details. */
93         pixman_image_t *hw_surface;
94         uint8_t depth;
95 };
96
97 static const char default_seat[] = "seat0";
98
99 static inline struct fbdev_output *
100 to_fbdev_output(struct weston_output *base)
101 {
102         return container_of(base, struct fbdev_output, base);
103 }
104
105 static inline struct fbdev_backend *
106 to_fbdev_backend(struct weston_compositor *base)
107 {
108         return container_of(base->backend, struct fbdev_backend, base);
109 }
110
111 static void
112 fbdev_output_start_repaint_loop(struct weston_output *output)
113 {
114         struct timespec ts;
115
116         weston_compositor_read_presentation_clock(output->compositor, &ts);
117         weston_output_finish_frame(output, &ts, WP_PRESENTATION_FEEDBACK_INVALID);
118 }
119
120 static int
121 fbdev_output_repaint(struct weston_output *base, pixman_region32_t *damage)
122 {
123         struct fbdev_output *output = to_fbdev_output(base);
124         struct weston_compositor *ec = output->base.compositor;
125
126         /* Repaint the damaged region onto the back buffer. */
127         pixman_renderer_output_set_buffer(base, output->hw_surface);
128         ec->renderer->repaint_output(base, damage);
129
130         /* Update the damage region. */
131         pixman_region32_subtract(&ec->primary_plane.damage,
132                                  &ec->primary_plane.damage, damage);
133
134         /* Schedule the end of the frame. We do not sync this to the frame
135          * buffer clock because users who want that should be using the DRM
136          * compositor. FBIO_WAITFORVSYNC blocks and FB_ACTIVATE_VBL requires
137          * panning, which is broken in most kernel drivers.
138          *
139          * Finish the frame synchronised to the specified refresh rate. The
140          * refresh rate is given in mHz and the interval in ms. */
141         wl_event_source_timer_update(output->finish_frame_timer,
142                                      1000000 / output->mode.refresh);
143
144         return 0;
145 }
146
147 static int
148 finish_frame_handler(void *data)
149 {
150         struct fbdev_output *output = data;
151         struct timespec ts;
152
153         weston_compositor_read_presentation_clock(output->base.compositor, &ts);
154         weston_output_finish_frame(&output->base, &ts, 0);
155
156         return 1;
157 }
158
159 static pixman_format_code_t
160 calculate_pixman_format(struct fb_var_screeninfo *vinfo,
161                         struct fb_fix_screeninfo *finfo)
162 {
163         /* Calculate the pixman format supported by the frame buffer from the
164          * buffer's metadata. Return 0 if no known pixman format is supported
165          * (since this has depth 0 it's guaranteed to not conflict with any
166          * actual pixman format).
167          *
168          * Documentation on the vinfo and finfo structures:
169          *    http://www.mjmwired.net/kernel/Documentation/fb/api.txt
170          *
171          * TODO: Try a bit harder to support other formats, including setting
172          * the preferred format in the hardware. */
173         int type;
174
175         weston_log("Calculating pixman format from:\n"
176                    STAMP_SPACE " - type: %i (aux: %i)\n"
177                    STAMP_SPACE " - visual: %i\n"
178                    STAMP_SPACE " - bpp: %i (grayscale: %i)\n"
179                    STAMP_SPACE " - red: offset: %i, length: %i, MSB: %i\n"
180                    STAMP_SPACE " - green: offset: %i, length: %i, MSB: %i\n"
181                    STAMP_SPACE " - blue: offset: %i, length: %i, MSB: %i\n"
182                    STAMP_SPACE " - transp: offset: %i, length: %i, MSB: %i\n",
183                    finfo->type, finfo->type_aux, finfo->visual,
184                    vinfo->bits_per_pixel, vinfo->grayscale,
185                    vinfo->red.offset, vinfo->red.length, vinfo->red.msb_right,
186                    vinfo->green.offset, vinfo->green.length,
187                    vinfo->green.msb_right,
188                    vinfo->blue.offset, vinfo->blue.length,
189                    vinfo->blue.msb_right,
190                    vinfo->transp.offset, vinfo->transp.length,
191                    vinfo->transp.msb_right);
192
193         /* We only handle packed formats at the moment. */
194         if (finfo->type != FB_TYPE_PACKED_PIXELS)
195                 return 0;
196
197         /* We only handle true-colour frame buffers at the moment. */
198         switch(finfo->visual) {
199                 case FB_VISUAL_TRUECOLOR:
200                 case FB_VISUAL_DIRECTCOLOR:
201                         if (vinfo->grayscale != 0)
202                                 return 0;
203                 break;
204                 default:
205                         return 0;
206         }
207
208         /* We only support formats with MSBs on the left. */
209         if (vinfo->red.msb_right != 0 || vinfo->green.msb_right != 0 ||
210             vinfo->blue.msb_right != 0)
211                 return 0;
212
213         /* Work out the format type from the offsets. We only support RGBA and
214          * ARGB at the moment. */
215         type = PIXMAN_TYPE_OTHER;
216
217         if ((vinfo->transp.offset >= vinfo->red.offset ||
218              vinfo->transp.length == 0) &&
219             vinfo->red.offset >= vinfo->green.offset &&
220             vinfo->green.offset >= vinfo->blue.offset)
221                 type = PIXMAN_TYPE_ARGB;
222         else if (vinfo->red.offset >= vinfo->green.offset &&
223                  vinfo->green.offset >= vinfo->blue.offset &&
224                  vinfo->blue.offset >= vinfo->transp.offset)
225                 type = PIXMAN_TYPE_RGBA;
226
227         if (type == PIXMAN_TYPE_OTHER)
228                 return 0;
229
230         /* Build the format. */
231         return PIXMAN_FORMAT(vinfo->bits_per_pixel, type,
232                              vinfo->transp.length,
233                              vinfo->red.length,
234                              vinfo->green.length,
235                              vinfo->blue.length);
236 }
237
238 static int
239 calculate_refresh_rate(struct fb_var_screeninfo *vinfo)
240 {
241         uint64_t quot;
242
243         /* Calculate monitor refresh rate. Default is 60 Hz. Units are mHz. */
244         quot = (vinfo->upper_margin + vinfo->lower_margin + vinfo->yres);
245         quot *= (vinfo->left_margin + vinfo->right_margin + vinfo->xres);
246         quot *= vinfo->pixclock;
247
248         if (quot > 0) {
249                 uint64_t refresh_rate;
250
251                 refresh_rate = 1000000000000000LLU / quot;
252                 if (refresh_rate > 200000)
253                         refresh_rate = 200000; /* cap at 200 Hz */
254
255                 return refresh_rate;
256         }
257
258         return 60 * 1000; /* default to 60 Hz */
259 }
260
261 static int
262 fbdev_query_screen_info(struct fbdev_output *output, int fd,
263                         struct fbdev_screeninfo *info)
264 {
265         struct fb_var_screeninfo varinfo;
266         struct fb_fix_screeninfo fixinfo;
267
268         /* Probe the device for screen information. */
269         if (ioctl(fd, FBIOGET_FSCREENINFO, &fixinfo) < 0 ||
270             ioctl(fd, FBIOGET_VSCREENINFO, &varinfo) < 0) {
271                 return -1;
272         }
273
274         /* Store the pertinent data. */
275         info->x_resolution = varinfo.xres;
276         info->y_resolution = varinfo.yres;
277         info->width_mm = varinfo.width;
278         info->height_mm = varinfo.height;
279         info->bits_per_pixel = varinfo.bits_per_pixel;
280
281         info->buffer_length = fixinfo.smem_len;
282         info->line_length = fixinfo.line_length;
283         strncpy(info->id, fixinfo.id, sizeof(info->id));
284         info->id[sizeof(info->id)-1] = '\0';
285
286         info->pixel_format = calculate_pixman_format(&varinfo, &fixinfo);
287         info->refresh_rate = calculate_refresh_rate(&varinfo);
288
289         if (info->pixel_format == 0) {
290                 weston_log("Frame buffer uses an unsupported format.\n");
291                 return -1;
292         }
293
294         return 1;
295 }
296
297 static int
298 fbdev_set_screen_info(struct fbdev_output *output, int fd,
299                       struct fbdev_screeninfo *info)
300 {
301         struct fb_var_screeninfo varinfo;
302
303         /* Grab the current screen information. */
304         if (ioctl(fd, FBIOGET_VSCREENINFO, &varinfo) < 0) {
305                 return -1;
306         }
307
308         /* Update the information. */
309         varinfo.xres = info->x_resolution;
310         varinfo.yres = info->y_resolution;
311         varinfo.width = info->width_mm;
312         varinfo.height = info->height_mm;
313         varinfo.bits_per_pixel = info->bits_per_pixel;
314
315         /* Try to set up an ARGB (x8r8g8b8) pixel format. */
316         varinfo.grayscale = 0;
317         varinfo.transp.offset = 24;
318         varinfo.transp.length = 0;
319         varinfo.transp.msb_right = 0;
320         varinfo.red.offset = 16;
321         varinfo.red.length = 8;
322         varinfo.red.msb_right = 0;
323         varinfo.green.offset = 8;
324         varinfo.green.length = 8;
325         varinfo.green.msb_right = 0;
326         varinfo.blue.offset = 0;
327         varinfo.blue.length = 8;
328         varinfo.blue.msb_right = 0;
329
330         /* Set the device's screen information. */
331         if (ioctl(fd, FBIOPUT_VSCREENINFO, &varinfo) < 0) {
332                 return -1;
333         }
334
335         return 1;
336 }
337
338 static void fbdev_frame_buffer_destroy(struct fbdev_output *output);
339
340 /* Returns an FD for the frame buffer device. */
341 static int
342 fbdev_frame_buffer_open(struct fbdev_output *output, const char *fb_dev,
343                         struct fbdev_screeninfo *screen_info)
344 {
345         int fd = -1;
346
347         weston_log("Opening fbdev frame buffer.\n");
348
349         /* Open the frame buffer device. */
350         fd = open(fb_dev, O_RDWR | O_CLOEXEC);
351         if (fd < 0) {
352                 weston_log("Failed to open frame buffer device ‘%s’: %s\n",
353                            fb_dev, strerror(errno));
354                 return -1;
355         }
356
357         /* Grab the screen info. */
358         if (fbdev_query_screen_info(output, fd, screen_info) < 0) {
359                 weston_log("Failed to get frame buffer info: %s\n",
360                            strerror(errno));
361
362                 close(fd);
363                 return -1;
364         }
365
366         return fd;
367 }
368
369 /* Closes the FD on success or failure. */
370 static int
371 fbdev_frame_buffer_map(struct fbdev_output *output, int fd)
372 {
373         int retval = -1;
374
375         weston_log("Mapping fbdev frame buffer.\n");
376
377         /* Map the frame buffer. Write-only mode, since we don't want to read
378          * anything back (because it's slow). */
379         output->fb = mmap(NULL, output->fb_info.buffer_length,
380                           PROT_WRITE, MAP_SHARED, fd, 0);
381         if (output->fb == MAP_FAILED) {
382                 weston_log("Failed to mmap frame buffer: %s\n",
383                            strerror(errno));
384                 goto out_close;
385         }
386
387         /* Create a pixman image to wrap the memory mapped frame buffer. */
388         output->hw_surface =
389                 pixman_image_create_bits(output->fb_info.pixel_format,
390                                          output->fb_info.x_resolution,
391                                          output->fb_info.y_resolution,
392                                          output->fb,
393                                          output->fb_info.line_length);
394         if (output->hw_surface == NULL) {
395                 weston_log("Failed to create surface for frame buffer.\n");
396                 goto out_unmap;
397         }
398
399         /* Success! */
400         retval = 0;
401
402 out_unmap:
403         if (retval != 0 && output->fb != NULL)
404                 fbdev_frame_buffer_destroy(output);
405
406 out_close:
407         if (fd >= 0)
408                 close(fd);
409
410         return retval;
411 }
412
413 static void
414 fbdev_frame_buffer_destroy(struct fbdev_output *output)
415 {
416         weston_log("Destroying fbdev frame buffer.\n");
417
418         if (munmap(output->fb, output->fb_info.buffer_length) < 0)
419                 weston_log("Failed to munmap frame buffer: %s\n",
420                            strerror(errno));
421
422         output->fb = NULL;
423 }
424
425 static void fbdev_output_destroy(struct weston_output *base);
426 static void fbdev_output_disable(struct weston_output *base);
427
428 static int
429 fbdev_output_enable(struct weston_output *base)
430 {
431         struct fbdev_output *output = to_fbdev_output(base);
432         struct fbdev_backend *backend = to_fbdev_backend(base->compositor);
433         int fb_fd;
434         struct wl_event_loop *loop;
435
436         /* Create the frame buffer. */
437         fb_fd = fbdev_frame_buffer_open(output, output->device, &output->fb_info);
438         if (fb_fd < 0) {
439                 weston_log("Creating frame buffer failed.\n");
440                 return -1;
441         }
442
443         if (fbdev_frame_buffer_map(output, fb_fd) < 0) {
444                 weston_log("Mapping frame buffer failed.\n");
445                 return -1;
446         }
447
448         output->base.start_repaint_loop = fbdev_output_start_repaint_loop;
449         output->base.repaint = fbdev_output_repaint;
450
451         if (pixman_renderer_output_create(&output->base) < 0)
452                 goto out_hw_surface;
453
454         loop = wl_display_get_event_loop(backend->compositor->wl_display);
455         output->finish_frame_timer =
456                 wl_event_loop_add_timer(loop, finish_frame_handler, output);
457
458         weston_log("fbdev output %d×%d px\n",
459                    output->mode.width, output->mode.height);
460         weston_log_continue(STAMP_SPACE "guessing %d Hz and 96 dpi\n",
461                             output->mode.refresh / 1000);
462
463         return 0;
464
465 out_hw_surface:
466         pixman_image_unref(output->hw_surface);
467         output->hw_surface = NULL;
468         fbdev_frame_buffer_destroy(output);
469
470         return -1;
471 }
472
473 static int
474 fbdev_output_create(struct fbdev_backend *backend,
475                     const char *device)
476 {
477         struct fbdev_output *output;
478         int fb_fd;
479
480         weston_log("Creating fbdev output.\n");
481
482         output = zalloc(sizeof *output);
483         if (output == NULL)
484                 return -1;
485
486         output->backend = backend;
487         output->device = strdup(device);
488
489         /* Create the frame buffer. */
490         fb_fd = fbdev_frame_buffer_open(output, device, &output->fb_info);
491         if (fb_fd < 0) {
492                 weston_log("Creating frame buffer failed.\n");
493                 goto out_free;
494         }
495
496         output->base.name = strdup("fbdev");
497         output->base.destroy = fbdev_output_destroy;
498         output->base.disable = NULL;
499         output->base.enable = fbdev_output_enable;
500
501         weston_output_init(&output->base, backend->compositor);
502
503         /* only one static mode in list */
504         output->mode.flags =
505                 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
506         output->mode.width = output->fb_info.x_resolution;
507         output->mode.height = output->fb_info.y_resolution;
508         output->mode.refresh = output->fb_info.refresh_rate;
509         wl_list_init(&output->base.mode_list);
510         wl_list_insert(&output->base.mode_list, &output->mode.link);
511
512         output->base.current_mode = &output->mode;
513         output->base.subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN;
514         output->base.make = "unknown";
515         output->base.model = output->fb_info.id;
516
517         output->base.mm_width = output->fb_info.width_mm;
518         output->base.mm_height = output->fb_info.height_mm;
519
520         close(fb_fd);
521
522         weston_compositor_add_pending_output(&output->base, backend->compositor);
523
524         return 0;
525
526 out_free:
527         free(output->device);
528         free(output);
529
530         return -1;
531 }
532
533 static void
534 fbdev_output_destroy(struct weston_output *base)
535 {
536         struct fbdev_output *output = to_fbdev_output(base);
537
538         weston_log("Destroying fbdev output.\n");
539
540         /* Close the frame buffer. */
541         fbdev_output_disable(base);
542
543         if (base->renderer_state != NULL)
544                 pixman_renderer_output_destroy(base);
545
546         /* Remove the output. */
547         weston_output_destroy(&output->base);
548
549         free(output->device);
550         free(output);
551 }
552
553 /* strcmp()-style return values. */
554 static int
555 compare_screen_info (const struct fbdev_screeninfo *a,
556                      const struct fbdev_screeninfo *b)
557 {
558         if (a->x_resolution == b->x_resolution &&
559             a->y_resolution == b->y_resolution &&
560             a->width_mm == b->width_mm &&
561             a->height_mm == b->height_mm &&
562             a->bits_per_pixel == b->bits_per_pixel &&
563             a->pixel_format == b->pixel_format &&
564             a->refresh_rate == b->refresh_rate)
565                 return 0;
566
567         return 1;
568 }
569
570 static int
571 fbdev_output_reenable(struct fbdev_backend *backend,
572                       struct weston_output *base)
573 {
574         struct fbdev_output *output = to_fbdev_output(base);
575         struct fbdev_screeninfo new_screen_info;
576         int fb_fd;
577         char *device;
578
579         weston_log("Re-enabling fbdev output.\n");
580
581         /* Create the frame buffer. */
582         fb_fd = fbdev_frame_buffer_open(output, output->device,
583                                         &new_screen_info);
584         if (fb_fd < 0) {
585                 weston_log("Creating frame buffer failed.\n");
586                 goto err;
587         }
588
589         /* Check whether the frame buffer details have changed since we were
590          * disabled. */
591         if (compare_screen_info (&output->fb_info, &new_screen_info) != 0) {
592                 /* Perform a mode-set to restore the old mode. */
593                 if (fbdev_set_screen_info(output, fb_fd,
594                                           &output->fb_info) < 0) {
595                         weston_log("Failed to restore mode settings. "
596                                    "Attempting to re-open output anyway.\n");
597                 }
598
599                 close(fb_fd);
600
601                 /* Remove and re-add the output so that resources depending on
602                  * the frame buffer X/Y resolution (such as the shadow buffer)
603                  * are re-initialised. */
604                 device = strdup(output->device);
605                 fbdev_output_destroy(&output->base);
606                 fbdev_output_create(backend, device);
607                 free(device);
608
609                 return 0;
610         }
611
612         /* Map the device if it has the same details as before. */
613         if (fbdev_frame_buffer_map(output, fb_fd) < 0) {
614                 weston_log("Mapping frame buffer failed.\n");
615                 goto err;
616         }
617
618         return 0;
619
620 err:
621         return -1;
622 }
623
624 /* NOTE: This leaves output->fb_info populated, caching data so that if
625  * fbdev_output_reenable() is called again, it can determine whether a mode-set
626  * is needed. */
627 static void
628 fbdev_output_disable(struct weston_output *base)
629 {
630         struct fbdev_output *output = to_fbdev_output(base);
631
632         weston_log("Disabling fbdev output.\n");
633
634         if (output->hw_surface != NULL) {
635                 pixman_image_unref(output->hw_surface);
636                 output->hw_surface = NULL;
637         }
638
639         fbdev_frame_buffer_destroy(output);
640 }
641
642 static void
643 fbdev_backend_destroy(struct weston_compositor *base)
644 {
645         struct fbdev_backend *backend = to_fbdev_backend(base);
646
647         udev_input_destroy(&backend->input);
648
649         /* Destroy the output. */
650         weston_compositor_shutdown(base);
651
652         /* Chain up. */
653         weston_launcher_destroy(base->launcher);
654
655         free(backend);
656 }
657
658 static void
659 session_notify(struct wl_listener *listener, void *data)
660 {
661         struct weston_compositor *compositor = data;
662         struct fbdev_backend *backend = to_fbdev_backend(compositor);
663         struct weston_output *output;
664
665         if (compositor->session_active) {
666                 weston_log("entering VT\n");
667                 compositor->state = backend->prev_state;
668
669                 wl_list_for_each(output, &compositor->output_list, link) {
670                         fbdev_output_reenable(backend, output);
671                 }
672
673                 weston_compositor_damage_all(compositor);
674
675                 udev_input_enable(&backend->input);
676         } else {
677                 weston_log("leaving VT\n");
678                 udev_input_disable(&backend->input);
679
680                 wl_list_for_each(output, &compositor->output_list, link) {
681                         fbdev_output_disable(output);
682                 }
683
684                 backend->prev_state = compositor->state;
685                 weston_compositor_offscreen(compositor);
686
687                 /* If we have a repaint scheduled (from the idle handler), make
688                  * sure we cancel that so we don't try to pageflip when we're
689                  * vt switched away.  The OFFSCREEN state will prevent
690                  * further attempts at repainting.  When we switch
691                  * back, we schedule a repaint, which will process
692                  * pending frame callbacks. */
693
694                 wl_list_for_each(output,
695                                  &compositor->output_list, link) {
696                         output->repaint_needed = 0;
697                 }
698         }
699 }
700
701 static void
702 fbdev_restore(struct weston_compositor *compositor)
703 {
704         weston_launcher_restore(compositor->launcher);
705 }
706
707 static struct fbdev_backend *
708 fbdev_backend_create(struct weston_compositor *compositor,
709                      struct weston_fbdev_backend_config *param)
710 {
711         struct fbdev_backend *backend;
712         const char *seat_id = default_seat;
713
714         weston_log("initializing fbdev backend\n");
715
716         backend = zalloc(sizeof *backend);
717         if (backend == NULL)
718                 return NULL;
719
720         backend->compositor = compositor;
721         if (weston_compositor_set_presentation_clock_software(
722                                                         compositor) < 0)
723                 goto out_compositor;
724
725         backend->udev = udev_new();
726         if (backend->udev == NULL) {
727                 weston_log("Failed to initialize udev context.\n");
728                 goto out_compositor;
729         }
730
731         /* Set up the TTY. */
732         backend->session_listener.notify = session_notify;
733         wl_signal_add(&compositor->session_signal,
734                       &backend->session_listener);
735         compositor->launcher =
736                 weston_launcher_connect(compositor, param->tty, "seat0", false);
737         if (!compositor->launcher) {
738                 weston_log("fatal: fbdev backend should be run "
739                            "using weston-launch binary or as root\n");
740                 goto out_udev;
741         }
742
743         backend->base.destroy = fbdev_backend_destroy;
744         backend->base.restore = fbdev_restore;
745
746         backend->prev_state = WESTON_COMPOSITOR_ACTIVE;
747
748         weston_setup_vt_switch_bindings(compositor);
749
750         if (pixman_renderer_init(compositor) < 0)
751                 goto out_launcher;
752
753         if (fbdev_output_create(backend, param->device) < 0)
754                 goto out_launcher;
755
756         udev_input_init(&backend->input, compositor, backend->udev,
757                         seat_id, param->configure_device);
758
759         compositor->backend = &backend->base;
760         return backend;
761
762 out_launcher:
763         weston_launcher_destroy(compositor->launcher);
764
765 out_udev:
766         udev_unref(backend->udev);
767
768 out_compositor:
769         weston_compositor_shutdown(compositor);
770         free(backend);
771
772         return NULL;
773 }
774
775 static void
776 config_init_to_defaults(struct weston_fbdev_backend_config *config)
777 {
778         /* TODO: Ideally, available frame buffers should be enumerated using
779          * udev, rather than passing a device node in as a parameter. */
780         config->tty = 0; /* default to current tty */
781         config->device = "/dev/fb0"; /* default frame buffer */
782 }
783
784 WL_EXPORT int
785 weston_backend_init(struct weston_compositor *compositor,
786                     struct weston_backend_config *config_base)
787 {
788         struct fbdev_backend *b;
789         struct weston_fbdev_backend_config config = {{ 0, }};
790
791         if (config_base == NULL ||
792             config_base->struct_version != WESTON_FBDEV_BACKEND_CONFIG_VERSION ||
793             config_base->struct_size > sizeof(struct weston_fbdev_backend_config)) {
794                 weston_log("fbdev backend config structure is invalid\n");
795                 return -1;
796         }
797
798         config_init_to_defaults(&config);
799         memcpy(&config, config_base, config_base->struct_size);
800
801         b = fbdev_backend_create(compositor, &config);
802         if (b == NULL)
803                 return -1;
804         return 0;
805 }