Move source files to src/libtdm-fbdev 39/256439/1
authorJunkyeong Kim <jk0430.kim@samsung.com>
Fri, 2 Apr 2021 10:51:19 +0000 (19:51 +0900)
committerJunkyeong Kim <jk0430.kim@samsung.com>
Fri, 2 Apr 2021 10:51:22 +0000 (19:51 +0900)
Change-Id: Ia86f2662cc65740631ec3444193ae5a357a7d1ad
Signed-off-by: Junkyeong Kim <jk0430.kim@samsung.com>
configure.ac
src/Makefile.am
src/libtdm-fbdev/Makefile.am [new file with mode: 0644]
src/libtdm-fbdev/tdm_fbdev.c [new file with mode: 0644]
src/libtdm-fbdev/tdm_fbdev.h [new file with mode: 0644]
src/libtdm-fbdev/tdm_fbdev_display.c [new file with mode: 0644]
src/tdm_fbdev.c [deleted file]
src/tdm_fbdev.h [deleted file]
src/tdm_fbdev_display.c [deleted file]

index bf3d41f4c661aa5b4676c73be1696a084390aa00..dd432221d33ecc9103f1ed58d29074488f229481 100644 (file)
@@ -51,6 +51,7 @@ AC_SUBST(TDM_MODULE_PATH)
 # For enumerating devices in test case
 AC_OUTPUT([
        Makefile
+       src/libtdm-fbdev/Makefile
        src/Makefile])
 
 echo ""
index 5bae8479e853f967563676456bf7e092942ec8a2..f4f7686fcf7d3013b41cc94f737b610c9f244ba9 100644 (file)
@@ -1,12 +1 @@
-AM_CFLAGS = \
-       $(TDM_DRM_CFLAGS) \
-       -I$(top_srcdir)/src
-
-libtdm_fbdev_la_LTLIBRARIES = libtdm-fbdev.la
-libtdm_fbdev_ladir = $(TDM_MODULE_PATH)
-libtdm_fbdev_la_LDFLAGS = -module -avoid-version
-libtdm_fbdev_la_LIBADD = $(TDM_DRM_LIBS) -ldl
-
-libtdm_fbdev_la_SOURCES = \
-       tdm_fbdev_display.c \
-       tdm_fbdev.c
+SUBDIRS = libtdm-fbdev
diff --git a/src/libtdm-fbdev/Makefile.am b/src/libtdm-fbdev/Makefile.am
new file mode 100644 (file)
index 0000000..5bae847
--- /dev/null
@@ -0,0 +1,12 @@
+AM_CFLAGS = \
+       $(TDM_DRM_CFLAGS) \
+       -I$(top_srcdir)/src
+
+libtdm_fbdev_la_LTLIBRARIES = libtdm-fbdev.la
+libtdm_fbdev_ladir = $(TDM_MODULE_PATH)
+libtdm_fbdev_la_LDFLAGS = -module -avoid-version
+libtdm_fbdev_la_LIBADD = $(TDM_DRM_LIBS) -ldl
+
+libtdm_fbdev_la_SOURCES = \
+       tdm_fbdev_display.c \
+       tdm_fbdev.c
diff --git a/src/libtdm-fbdev/tdm_fbdev.c b/src/libtdm-fbdev/tdm_fbdev.c
new file mode 100644 (file)
index 0000000..33ef4ef
--- /dev/null
@@ -0,0 +1,284 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tdm_fbdev.h"
+#include <tdm_helper.h>
+
+#define TDM_FBDEV_NAME "fbdev"
+
+static tdm_fbdev_data *fbdev_data;
+
+static int
+_tdm_fbdev_open_fbdev(void)
+{
+       const char *name = "/dev/fb0";
+       int fd = -1;
+
+       fd = open(name, O_RDWR);
+       if (fd < 0) {
+               TDM_ERR("Cannot open fbdev device.. search by udev");
+               goto close;
+       }
+
+       /*
+        * TODO: If we failed directly to open framebuffer device
+        * we would try to open it through udev
+        */
+
+close:
+
+       return fd;
+}
+
+static tdm_error
+_tdm_fbdev_init_internal(void)
+{
+       struct fb_fix_screeninfo *finfo = calloc(1, sizeof(struct fb_fix_screeninfo));
+       struct fb_var_screeninfo *vinfo = calloc(1, sizeof(struct fb_var_screeninfo));
+       int ret = -1;
+
+       ret = ioctl(fbdev_data->fbdev_fd, FBIOGET_VSCREENINFO, vinfo);
+       if (ret < 0) {
+               TDM_ERR("FBIOGET_VSCREENINFO ioctl failed errno=%d", errno);
+               goto close_1;
+       }
+
+       vinfo->reserved[0] = 0;
+       vinfo->reserved[1] = 0;
+       vinfo->reserved[2] = 0;
+       vinfo->xoffset = 0;
+       vinfo->yoffset = 0;
+       vinfo->activate = FB_ACTIVATE_NOW;
+
+       /*
+        * Explicitly request 32 bits per pixel colors with corresponding
+        * red, blue and green color offsets and length of colors
+        */
+       vinfo->bits_per_pixel   = 32;
+       vinfo->red.offset               = 16;
+       vinfo->red.length               = 8;
+       vinfo->green.offset             = 8;
+       vinfo->green.length             = 8;
+       vinfo->blue.offset              = 0;
+       vinfo->blue.length              = 8;
+       vinfo->transp.offset    = 0;
+       vinfo->transp.length    = 0;
+
+       vinfo->yres_virtual = vinfo->yres * MAX_BUF;
+       ret = ioctl(fbdev_data->fbdev_fd, FBIOPAN_DISPLAY, vinfo);
+       if (ret < 0)
+               TDM_ERR("FBIOPAN_DISPLAY ioctl failed, errno=%d", errno);
+
+       ret = ioctl(fbdev_data->fbdev_fd, FBIOGET_FSCREENINFO, finfo);
+       if (ret < 0) {
+               TDM_ERR("FBIOGET_FSCREENINFO ioctl failed, errno=%d", errno);
+               goto close_1;
+       }
+
+       if (finfo->smem_len <= 0) {
+               TDM_ERR("Length of frame buffer mem less then 0");
+               goto close_1;
+       }
+
+       fbdev_data->vinfo = vinfo;
+       fbdev_data->finfo = finfo;
+
+       /*
+        * Output framebuffer's related information
+        */
+       TDM_INFO("\n"
+                       " VInfo\n"
+                       "   fb           = %d\n"
+                       "   xres         = %d px \n"
+                       "   yres         = %d px \n"
+                       "   xres_virtual = %d px \n"
+                       "   yres_virtual = %d px \n"
+                       "   bpp          = %d    \n"
+                       "   r            = %2u:%u\n"
+                       "   g            = %2u:%u\n"
+                       "   b            = %2u:%u\n"
+                       "   t            = %2u:%u\n"
+                       "   active       = %d    \n"
+                       "   width        = %d mm \n"
+                       "   height       = %d mm \n",
+                       fbdev_data->fbdev_fd,
+                       vinfo->xres,
+                       vinfo->yres,
+                       vinfo->xres_virtual,
+                       vinfo->yres_virtual,
+                       vinfo->bits_per_pixel,
+                       vinfo->red.offset, vinfo->red.length,
+                       vinfo->green.offset, vinfo->green.length,
+                       vinfo->blue.offset, vinfo->blue.length,
+                       vinfo->transp.offset, vinfo->transp.length,
+                       vinfo->activate,
+                       vinfo->width,
+                       vinfo->height);
+
+       TDM_INFO("\n"
+                       " FInfo\n"
+                       "   id          = %s\n"
+                       "   smem_len    = %d\n"
+                       "   line_length = %d\n",
+                       finfo->id,
+                       finfo->smem_len,
+                       finfo->line_length);
+
+       return TDM_ERROR_NONE;
+close_1:
+       ret = TDM_ERROR_OPERATION_FAILED;
+       return ret;
+}
+
+void
+tdm_fbdev_deinit(tdm_backend_data *bdata)
+{
+       if (fbdev_data != bdata)
+               return;
+
+       TDM_INFO("deinit");
+
+       close(fbdev_data->fbdev_fd);
+
+       tdm_fbdev_destroy_layer(fbdev_data);
+       tdm_fbdev_destroy_output(fbdev_data);
+
+       if (fbdev_data->vinfo)
+               free(fbdev_data->vinfo);
+
+       if (fbdev_data->finfo)
+               free(fbdev_data->finfo);
+
+       free(fbdev_data);
+       fbdev_data = NULL;
+}
+
+tdm_backend_data*
+tdm_fbdev_init(tdm_display *dpy, tdm_error *error)
+{
+       tdm_func_display fbdev_func_display;
+       tdm_func_output fbdev_func_output;
+       tdm_func_layer fbdev_func_layer;
+       tdm_error ret;
+
+       if (!dpy) {
+               TDM_ERR("display is null");
+               if (error)
+                       *error = TDM_ERROR_BAD_REQUEST;
+               return NULL;
+       }
+
+       if (fbdev_data) {
+               TDM_ERR("failed: init twice");
+               if (error)
+                       *error = TDM_ERROR_BAD_REQUEST;
+               return NULL;
+       }
+
+       fbdev_data = calloc(1, sizeof(struct _tdm_fbdev_data));
+       if (!fbdev_data) {
+               TDM_ERR("alloc failed");
+               if (error)
+                       *error = TDM_ERROR_OUT_OF_MEMORY;
+               return NULL;
+       }
+
+       LIST_INITHEAD(&fbdev_data->buffer_list);
+
+       memset(&fbdev_func_display, 0, sizeof(fbdev_func_display));
+       fbdev_func_display.display_get_capability = fbdev_display_get_capability;
+       fbdev_func_display.display_get_outputs = fbdev_display_get_outputs;
+       fbdev_func_display.display_get_fd = NULL;
+       fbdev_func_display.display_handle_events = NULL;
+
+       memset(&fbdev_func_output, 0, sizeof(fbdev_func_output));
+       fbdev_func_output.output_get_capability = fbdev_output_get_capability;
+       fbdev_func_output.output_get_layers = fbdev_output_get_layers;
+       fbdev_func_output.output_set_property = fbdev_output_set_property;
+       fbdev_func_output.output_get_property = fbdev_output_get_property;
+       fbdev_func_output.output_wait_vblank = fbdev_output_wait_vblank;
+       fbdev_func_output.output_set_vblank_handler = fbdev_output_set_vblank_handler;
+       fbdev_func_output.output_commit = fbdev_output_commit;
+       fbdev_func_output.output_set_commit_handler = fbdev_output_set_commit_handler;
+       fbdev_func_output.output_set_dpms = fbdev_output_set_dpms;
+       fbdev_func_output.output_get_dpms = fbdev_output_get_dpms;
+       fbdev_func_output.output_set_mode = fbdev_output_set_mode;
+       fbdev_func_output.output_get_mode = fbdev_output_get_mode;
+
+       memset(&fbdev_func_layer, 0, sizeof(fbdev_func_layer));
+       fbdev_func_layer.layer_get_capability = fbdev_layer_get_capability;
+       fbdev_func_layer.layer_set_property = fbdev_layer_set_property;
+       fbdev_func_layer.layer_get_property = fbdev_layer_get_property;
+       fbdev_func_layer.layer_set_info = fbdev_layer_set_info;
+       fbdev_func_layer.layer_get_info = fbdev_layer_get_info;
+       fbdev_func_layer.layer_set_buffer = fbdev_layer_set_buffer;
+       fbdev_func_layer.layer_unset_buffer = fbdev_layer_unset_buffer;
+
+       ret = tdm_backend_register_func_display(dpy, &fbdev_func_display);
+       if (ret != TDM_ERROR_NONE)
+               goto failed;
+
+       ret = tdm_backend_register_func_output(dpy, &fbdev_func_output);
+       if (ret != TDM_ERROR_NONE)
+               goto failed;
+
+       ret = tdm_backend_register_func_layer(dpy, &fbdev_func_layer);
+       if (ret != TDM_ERROR_NONE)
+               goto failed;
+
+       fbdev_data->dpy = dpy;
+
+       fbdev_data->fbdev_fd = _tdm_fbdev_open_fbdev();
+       if (fbdev_data->fbdev_fd < 0) {
+               ret = TDM_ERROR_OPERATION_FAILED;
+               goto failed;
+       }
+
+       ret = _tdm_fbdev_init_internal();
+       if (ret != TDM_ERROR_NONE) {
+               TDM_INFO("init of framebuffer failed");
+               goto failed;
+       }
+
+       ret = tdm_fbdev_creat_output(fbdev_data);
+       if (ret != TDM_ERROR_NONE) {
+               TDM_INFO("init of output failed");
+               goto failed_2;
+       }
+
+       ret = tdm_fbdev_creat_layer(fbdev_data);
+       if (ret != TDM_ERROR_NONE) {
+               TDM_INFO("init of output failed");
+               goto failed_3;
+       }
+
+       TDM_INFO("init success!");
+
+       if (error)
+               *error = TDM_ERROR_NONE;
+
+       return (tdm_backend_data*) fbdev_data;
+
+failed_3:
+        tdm_fbdev_destroy_layer(fbdev_data);
+failed_2:
+       tdm_fbdev_destroy_output(fbdev_data);
+
+failed:
+       if (error)
+               *error = ret;
+
+       tdm_fbdev_deinit(fbdev_data);
+
+       TDM_ERR("init failed!");
+       return NULL;
+}
+
+tdm_backend_module tdm_backend_module_data = {
+       "fbdev",
+       "Samsung",
+       TDM_BACKEND_SET_ABI_VERSION(1, 1),
+       tdm_fbdev_init,
+       tdm_fbdev_deinit
+};
diff --git a/src/libtdm-fbdev/tdm_fbdev.h b/src/libtdm-fbdev/tdm_fbdev.h
new file mode 100644 (file)
index 0000000..bc66fb0
--- /dev/null
@@ -0,0 +1,164 @@
+#ifndef _TDM_fbdev_H_
+#define _TDM_fbdev_H_
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <errno.h>
+#include <unistd.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+
+#include <linux/fb.h>
+
+#include <tbm_surface.h>
+#include <tbm_surface_internal.h>
+#include <tdm_backend.h>
+#include <tdm_log.h>
+#include <tdm_list.h>
+
+#define MAX_BUF 1
+
+/* fbdev backend functions (display) */
+tdm_error              fbdev_display_get_capability(tdm_backend_data *bdata, tdm_caps_display *caps);
+tdm_output**   fbdev_display_get_outputs(tdm_backend_data *bdata, int *count, tdm_error *error);
+tdm_error              fbdev_display_get_fd(tdm_backend_data *bdata, int *fd);
+tdm_error              fbdev_display_handle_events(tdm_backend_data *bdata);
+tdm_pp*                        fbdev_display_create_pp(tdm_backend_data *bdata, tdm_error *error);
+tdm_error              fbdev_output_get_capability(tdm_output *output, tdm_caps_output *caps);
+tdm_layer**            fbdev_output_get_layers(tdm_output *output, int *count, tdm_error *error);
+tdm_error              fbdev_output_set_property(tdm_output *output, unsigned int id, tdm_value value);
+tdm_error              fbdev_output_get_property(tdm_output *output, unsigned int id, tdm_value *value);
+tdm_error              fbdev_output_wait_vblank(tdm_output *output, int interval, int sync, void *user_data);
+tdm_error              fbdev_output_set_vblank_handler(tdm_output *output, tdm_output_vblank_handler func);
+tdm_error              fbdev_output_commit(tdm_output *output, int sync, void *user_data);
+tdm_error              fbdev_output_set_commit_handler(tdm_output *output, tdm_output_commit_handler func);
+tdm_error              fbdev_output_set_dpms(tdm_output *output, tdm_output_dpms dpms_value);
+tdm_error              fbdev_output_get_dpms(tdm_output *output, tdm_output_dpms *dpms_value);
+tdm_error              fbdev_output_set_mode(tdm_output *output, const tdm_output_mode *mode);
+tdm_error              fbdev_output_get_mode(tdm_output *output, const tdm_output_mode **mode);
+tdm_error              fbdev_layer_get_capability(tdm_layer *layer, tdm_caps_layer *caps);
+tdm_error              fbdev_layer_set_property(tdm_layer *layer, unsigned int id, tdm_value value);
+tdm_error              fbdev_layer_get_property(tdm_layer *layer, unsigned int id, tdm_value *value);
+tdm_error              fbdev_layer_set_info(tdm_layer *layer, tdm_info_layer *info);
+tdm_error              fbdev_layer_get_info(tdm_layer *layer, tdm_info_layer *info);
+tdm_error              fbdev_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer);
+tdm_error              fbdev_layer_unset_buffer(tdm_layer *layer);
+
+/* Framebuffer moudel's internal macros, functions, structures */
+#define NEVER_GET_HERE() TDM_ERR("** NEVER GET HERE **")
+
+#define RETURN_VAL_IF_FAIL(cond, val) {\
+       if (!(cond)) {\
+               TDM_ERR("'%s' failed", #cond);\
+               return val;\
+       }       \
+}
+
+typedef struct _tdm_fbdev_output_data tdm_fbdev_output_data;
+typedef struct _tdm_fbdev_layer_data tdm_fbdev_layer_data;
+typedef struct _tdm_fbdev_display_buffer tdm_fbdev_display_buffer;
+
+typedef struct _tdm_fbdev_data {
+       tdm_fbdev_output_data *fbdev_output;
+
+       int fbdev_fd;
+
+       tdm_display *dpy;
+
+       struct fb_fix_screeninfo *finfo;
+       struct fb_var_screeninfo *vinfo;
+
+       struct list_head buffer_list;
+} tdm_fbdev_data;
+
+struct _tdm_fbdev_output_data {
+       tdm_fbdev_data *fbdev_data;
+       tdm_fbdev_layer_data *fbdev_layer;
+
+       uint32_t width;
+       uint32_t height;
+       uint32_t pitch;
+       uint32_t bpp;
+       size_t size;
+       uint32_t max_width;
+       uint32_t max_height;
+
+       /*
+        * Poinetr to Framebuffers's mapped memory
+        */
+       void *mem;
+
+       int count_modes;
+       tdm_output_mode *output_modes;
+       int mode_changed;
+
+       /*
+        * Frambuffer device back end currently support only one mode
+        */
+       const tdm_output_mode *current_mode;
+
+       tdm_output_type connector_type;
+       tdm_output_conn_status status;
+       unsigned int connector_type_id;
+
+       tdm_output_dpms dpms_value;
+
+       /*
+        * Event handlers
+        */
+       tdm_output_vblank_handler vblank_func;
+       tdm_output_commit_handler commit_func;
+
+       void *user_data;
+
+       /*
+        * Fake flags are used to simulate event-operated back end. Since tdm
+        *  library assumes its back ends to be event-operated and Framebuffer
+        *  device is not event-operated we have to make fake events
+        */
+       int is_vblank;
+       int is_commit;
+
+       int sequence;
+
+};
+
+struct _tdm_fbdev_layer_data {
+       tdm_fbdev_data *fbdev_data;
+       tdm_fbdev_output_data *fbdev_output;
+
+       tdm_fbdev_display_buffer *display_buffer;
+       int display_buffer_changed;
+
+       tdm_layer_capability capabilities;
+       tdm_info_layer info;
+       int info_changed;
+};
+
+enum {
+       DOWN = 0,
+       UP,
+};
+
+struct _tdm_fbdev_display_buffer {
+       struct list_head link;
+
+       int width;
+       int height;
+
+       tbm_surface_h buffer;
+};
+
+tdm_error      tdm_fbdev_creat_output(tdm_fbdev_data *fbdev_data);
+void           tdm_fbdev_destroy_output(tdm_fbdev_data *fbdev_data);
+
+tdm_error      tdm_fbdev_creat_layer(tdm_fbdev_data *fbdev_data);
+void           tdm_fbdev_destroy_layer(tdm_fbdev_data *fbdev_data);
+
+#endif /* _TDM_fbdev_H_ */
diff --git a/src/libtdm-fbdev/tdm_fbdev_display.c b/src/libtdm-fbdev/tdm_fbdev_display.c
new file mode 100644 (file)
index 0000000..63ee64e
--- /dev/null
@@ -0,0 +1,834 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <tdm_helper.h>
+#include <stdint.h>
+#include "tdm_fbdev.h"
+
+#include <xf86drm.h>
+#include <libudev.h>
+
+/*
+ * Framebuffer device supported formats
+ */
+static tbm_format supported_formats[] = {
+       /*
+        * TODO: add support of 16 bit formats
+        */
+       TBM_FORMAT_ARGB8888,
+       TBM_FORMAT_ABGR8888,
+       TBM_FORMAT_RGBA8888,
+       TBM_FORMAT_BGRA8888,
+};
+
+static tdm_fbdev_display_buffer*
+_tdm_fbdev_display_find_buffer(tdm_fbdev_data *fbdev_data, tbm_surface_h buffer)
+{
+       tdm_fbdev_display_buffer *display_buffer = NULL;
+
+       LIST_FOR_EACH_ENTRY(display_buffer, &fbdev_data->buffer_list, link)
+       {
+               if (display_buffer->buffer == buffer)
+                       return display_buffer;
+       }
+
+       return NULL;
+}
+
+static void
+_tdm_fbdev_display_cb_destroy_buffer(tbm_surface_h buffer, void *user_data)
+{
+       tdm_fbdev_data *fbdev_data;
+       tdm_fbdev_display_buffer *display_buffer;
+
+       if (!user_data) {
+               TDM_ERR("no user_data");
+               return;
+       }
+       if (!buffer) {
+               TDM_ERR("no buffer");
+               return;
+       }
+
+       fbdev_data = (tdm_fbdev_data *) user_data;
+
+       display_buffer = _tdm_fbdev_display_find_buffer(fbdev_data, buffer);
+       if (!display_buffer) {
+               TDM_ERR("no display_buffer");
+               return;
+       }
+
+       LIST_DEL(&display_buffer->link);
+
+       free(display_buffer);
+}
+
+
+static inline uint32_t
+_get_refresh(struct fb_var_screeninfo *timing)
+{
+       uint32_t pixclock, hfreq, htotal, vtotal;
+
+       pixclock = PICOS2KHZ(timing->pixclock) * 1000;
+
+       htotal = timing->xres + timing->right_margin + timing->hsync_len + timing->left_margin;
+       vtotal = timing->yres + timing->lower_margin + timing->vsync_len + timing->upper_margin;
+
+       if (timing->vmode & FB_VMODE_INTERLACED)
+               vtotal /= 2;
+       if (timing->vmode & FB_VMODE_DOUBLE)
+               vtotal *= 2;
+
+       hfreq = pixclock / htotal;
+       return hfreq / vtotal;
+}
+
+/*
+ * Convert fb_var_screeninfo to tdm_output_mode
+ */
+static inline void
+_tdm_fbdev_display_to_tdm_mode(struct fb_var_screeninfo *timing, tdm_output_mode *mode)
+{
+
+       if (!timing->pixclock)
+               return;
+
+       mode->clock = timing->pixclock / 1000;
+       mode->vrefresh = _get_refresh(timing);
+       mode->hdisplay = timing->xres;
+       mode->hsync_start = mode->hdisplay + timing->right_margin;
+       mode->hsync_end = mode->hsync_start + timing->hsync_len;
+       mode->htotal = mode->hsync_end + timing->left_margin;
+
+       mode->vdisplay = timing->yres;
+       mode->vsync_start = mode->vdisplay + timing->lower_margin;
+       mode->vsync_end = mode->vsync_start + timing->vsync_len;
+       mode->vtotal = mode->vsync_end + timing->upper_margin;
+
+       int interlaced = !!(timing->vmode & FB_VMODE_INTERLACED);
+       snprintf(mode->name, TDM_NAME_LEN, "%dx%d%s", mode->hdisplay, mode->vdisplay, interlaced ? "i" : "");
+}
+
+tdm_error
+tdm_fbdev_creat_output(tdm_fbdev_data *fbdev_data)
+{
+       tdm_fbdev_output_data *output = NULL;
+       size_t size;
+       int i = 0;
+
+       output = calloc(1, sizeof(tdm_fbdev_output_data));
+       if (output == NULL) {
+               TDM_ERR("alloc output failed");
+               return TDM_ERROR_OUT_OF_MEMORY;
+       }
+
+       /*
+        * TODO: Size of framebuffer must be aligned to system page size before
+        *  it is mapped
+        */
+       size = fbdev_data->vinfo->xres * fbdev_data->vinfo->yres * fbdev_data->vinfo->bits_per_pixel / 8 * MAX_BUF;
+
+       TDM_INFO("\n" "MMaped size: %zu\n", size);
+
+       output->mem = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fbdev_data->fbdev_fd, 0);
+       if (output->mem == MAP_FAILED) {
+               TDM_ERR("MMap framebuffer failed, errno=%d", errno);
+               return TDM_ERROR_OPERATION_FAILED;
+       }
+
+       memset(output->mem, 0, size);
+
+       output->width = fbdev_data->vinfo->xres;
+       output->height = fbdev_data->vinfo->yres;
+       output->pitch = fbdev_data->vinfo->width;
+       output->bpp = fbdev_data->vinfo->bits_per_pixel;
+       output->size = size;
+       output->max_width = fbdev_data->vinfo->xres_virtual;
+       output->max_height = fbdev_data->vinfo->yres_virtual;
+
+       output->status = TDM_OUTPUT_CONN_STATUS_CONNECTED;
+       output->connector_type = TDM_OUTPUT_TYPE_LVDS;
+
+       output->is_vblank = DOWN;
+       output->is_commit = DOWN;
+       output->sequence = 1;
+
+       /*
+        * TODO: connector_type_id field relates to libdrm connector which framebuffer
+        *  does not know. It have to be checked whether softaware above us use this
+        *  field for its purposes.
+        */
+       output->connector_type_id = 1;
+
+       output->count_modes = 1;
+       output->output_modes = calloc(output->count_modes, sizeof(tdm_output_mode));
+       if (!output->output_modes) {
+               TDM_ERR("failed: alloc memory");
+               return TDM_ERROR_OUT_OF_MEMORY;
+       }
+
+       for (i = 0; i < output->count_modes; i++) {
+               _tdm_fbdev_display_to_tdm_mode(fbdev_data->vinfo, &output->output_modes[i]);
+
+               sprintf(output->output_modes[i].name, "%dx%d", fbdev_data->vinfo->xres, fbdev_data->vinfo->yres);
+       }
+
+       /*
+        * We currently support only one mode
+        */
+       if (output->count_modes == 1) {
+               output->current_mode = &output->output_modes[0];
+               output->status = TDM_OUTPUT_CONN_STATUS_MODE_SETTED;
+       }
+
+       output->fbdev_data = fbdev_data;
+       fbdev_data->fbdev_output = output;
+
+       return TDM_ERROR_NONE;
+}
+
+void
+tdm_fbdev_destroy_output(tdm_fbdev_data *fbdev_data)
+{
+       tdm_fbdev_output_data *fbdev_output = fbdev_data->fbdev_output;
+
+       if (fbdev_output == NULL)
+               goto close;
+
+       if (fbdev_output->mem == NULL)
+               goto close_2;
+
+       munmap(fbdev_output->mem, fbdev_output->size);
+
+       if (fbdev_output->output_modes == NULL)
+               goto close_2;
+
+       free(fbdev_output->output_modes);
+
+close_2:
+       free(fbdev_output);
+close:
+       return;
+}
+
+tdm_error
+tdm_fbdev_creat_layer(tdm_fbdev_data *fbdev_data)
+{
+       tdm_fbdev_layer_data *layer;
+       tdm_fbdev_output_data *fbdev_output = fbdev_data->fbdev_output;
+
+       /*
+        * Framebuffer does not support layer, therefore create only
+        *  one layer by libtdm's demand;
+        */
+       layer = calloc(1, sizeof(tdm_fbdev_layer_data));
+       if (layer == NULL) {
+               TDM_ERR("alloc output failed");
+               return TDM_ERROR_OUT_OF_MEMORY;
+       }
+
+       layer->capabilities = TDM_LAYER_CAPABILITY_PRIMARY | TDM_LAYER_CAPABILITY_GRAPHIC;
+
+       layer->fbdev_data = fbdev_data;
+       layer->fbdev_output = fbdev_output;
+       fbdev_output->fbdev_layer = layer;
+
+       return TDM_ERROR_NONE;
+}
+
+void
+tdm_fbdev_destroy_layer(tdm_fbdev_data *fbdev_data)
+{
+       tdm_fbdev_output_data *fbdev_output = fbdev_data->fbdev_output;
+       tdm_fbdev_layer_data *layer = fbdev_output->fbdev_layer;
+
+       if (layer != NULL)
+               free(layer);
+}
+
+tdm_error
+fbdev_display_get_capability(tdm_backend_data *bdata, tdm_caps_display *caps)
+{
+       RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER);
+
+       /*
+        * Framebuffer does not support layer, therefore create only
+        *  one layer by libtdm's demand;
+        */
+       caps->max_layer_count = 1;
+
+       return TDM_ERROR_NONE;
+}
+
+tdm_output**
+fbdev_display_get_outputs(tdm_backend_data *bdata, int *count, tdm_error *error)
+{
+       tdm_fbdev_data *fbdev_data = bdata;
+       tdm_fbdev_output_data *fbdev_output = fbdev_data->fbdev_output;
+       tdm_output **outputs;
+       tdm_error ret;
+
+       RETURN_VAL_IF_FAIL(fbdev_data, NULL);
+       RETURN_VAL_IF_FAIL(count, NULL);
+
+       if (fbdev_output == NULL) {
+               ret = TDM_ERROR_NONE;
+               goto failed_get;
+       }
+
+       /*
+        * Since it is Framebuffer device there is only one output
+        */
+       *count = 1;
+
+       /* will be freed in frontend */
+       outputs = calloc(*count, sizeof(tdm_fbdev_output_data*));
+       if (!outputs) {
+               TDM_ERR("failed: alloc memory");
+               *count = 0;
+               ret = TDM_ERROR_OUT_OF_MEMORY;
+               goto failed_get;
+       }
+
+       outputs[0] = fbdev_output;
+
+       if (error)
+               *error = TDM_ERROR_NONE;
+
+       return outputs;
+
+failed_get:
+
+       if (error)
+               *error = ret;
+       return NULL;
+}
+
+tdm_error
+fbdev_display_handle_events(tdm_backend_data *bdata)
+{
+       tdm_fbdev_data *fbdev_data = (tdm_fbdev_data *) bdata;
+       void *user_data;
+       tdm_fbdev_output_data *fbdev_output;
+       unsigned int sequence = 0;
+       unsigned int tv_sec = 0;
+       unsigned int tv_usec = 0;
+
+       RETURN_VAL_IF_FAIL(fbdev_data, TDM_ERROR_INVALID_PARAMETER);
+
+       fbdev_output = fbdev_data->fbdev_output;
+       user_data = fbdev_output->user_data;
+
+       RETURN_VAL_IF_FAIL(user_data, TDM_ERROR_INVALID_PARAMETER);
+
+       /*
+        (tdm_output *output, unsigned int sequence,
+        unsigned int tv_sec, unsigned int tv_usec,
+        void *user_data);
+        */
+
+       /*
+        * Framebuffer does not produce events
+        * Fake flags are used to simulate event-operated back end. Since tdm
+        *  library assumes its back ends to be event-operated and Framebuffer
+        *  device is not event-operated we have to make fake events
+        */
+       if (fbdev_output->is_vblank && fbdev_output->vblank_func) {
+               fbdev_output->is_vblank = DOWN;
+
+               fbdev_output->vblank_func((tdm_output *) fbdev_data, sequence, tv_sec, tv_usec, user_data);
+       }
+
+       if (fbdev_output->is_commit && fbdev_output->commit_func) {
+               fbdev_output->is_commit = DOWN;
+
+               fbdev_output->commit_func((tdm_output *) fbdev_data, sequence, tv_sec, tv_usec, user_data);
+       }
+
+       return TDM_ERROR_NONE;
+}
+
+tdm_error
+fbdev_output_get_capability(tdm_output *output, tdm_caps_output *caps)
+{
+       tdm_fbdev_output_data *fbdev_output = (tdm_fbdev_output_data *) output;
+       tdm_fbdev_data *fbdev_data = NULL;
+       tdm_error ret;
+       int i = 0;
+
+       RETURN_VAL_IF_FAIL(fbdev_output, TDM_ERROR_INVALID_PARAMETER);
+       RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER);
+
+       memset(caps, 0, sizeof(tdm_caps_output));
+
+       fbdev_data = fbdev_output->fbdev_data;
+
+       snprintf(caps->maker, TDM_NAME_LEN, "unknown");
+       snprintf(caps->model, TDM_NAME_LEN, "unknown");
+       snprintf(caps->name, TDM_NAME_LEN, "unknown");
+
+       caps->status = fbdev_output->status;
+       caps->type = fbdev_output->connector_type;
+       caps->type_id = fbdev_output->connector_type_id;
+
+       caps->mode_count = fbdev_output->count_modes;
+       caps->modes = calloc(caps->mode_count, sizeof(tdm_output_mode));
+       if (!caps->modes) {
+               ret = TDM_ERROR_OUT_OF_MEMORY;
+               TDM_ERR("alloc failed\n");
+               goto failed_get;
+       }
+
+       for (i = 0; i < caps->mode_count; i++)
+               caps->modes[i] = fbdev_output->output_modes[i];
+
+       caps->mmWidth = fbdev_data->vinfo->width;
+       caps->mmHeight = fbdev_data->vinfo->height;
+       caps->subpixel = -1;
+
+       caps->min_w = fbdev_output->width;
+       caps->min_h = fbdev_output->height;
+       caps->max_w = fbdev_output->max_width;
+       caps->max_h = fbdev_output->max_height;
+       caps->preferred_align = -1;
+
+       /*
+        * Framebuffer does not have output properties
+        */
+       caps->prop_count = 0;
+       caps->props = NULL;
+
+       return TDM_ERROR_NONE;
+
+failed_get:
+       memset(caps, 0, sizeof(tdm_caps_output));
+       return ret;
+}
+
+tdm_layer**
+fbdev_output_get_layers(tdm_output *output, int *count, tdm_error *error)
+{
+       tdm_fbdev_output_data *fbdev_output = (tdm_fbdev_output_data *) output;
+       tdm_layer **layers;
+       tdm_error ret;
+
+       RETURN_VAL_IF_FAIL(fbdev_output, NULL);
+       RETURN_VAL_IF_FAIL(count, NULL);
+
+       /*
+        * Framebuffer does not support layer, therefore create only
+        *  one layer by libtdm's demand;
+        */
+       *count = 1;
+
+       layers = calloc(*count, sizeof(tdm_layer));
+       if (layers == NULL) {
+               TDM_ERR("failed: alloc memory");
+               *count = 0;
+               ret = TDM_ERROR_OUT_OF_MEMORY;
+               goto failed_get;
+       }
+
+       layers[0] = fbdev_output->fbdev_layer;
+
+       if (error)
+               *error = TDM_ERROR_NONE;
+
+       return layers;
+
+failed_get:
+
+       if (error)
+               *error = ret;
+
+       return NULL;
+}
+
+tdm_error
+fbdev_output_set_property(tdm_output *output, unsigned int id, tdm_value value)
+{
+       /*
+        * Framebuffer does not have output properties
+        */
+       return TDM_ERROR_NONE;
+}
+
+tdm_error
+fbdev_output_get_property(tdm_output *output, unsigned int id, tdm_value *value)
+{
+       /*
+        * Framebuffer does not have output properties
+        */
+       return TDM_ERROR_NONE;
+}
+
+tdm_error
+fbdev_output_wait_vblank(tdm_output *output, int interval, int sync, void *user_data)
+{
+       tdm_fbdev_output_data *fbdev_output = (tdm_fbdev_output_data *) output;
+       tdm_fbdev_data *fbdev_data;
+
+       int crtc = 0;
+       int ret;
+
+       RETURN_VAL_IF_FAIL(fbdev_output, TDM_ERROR_INVALID_PARAMETER);
+
+       /*
+        * Frame buffer device does not support asynchronous events, that is
+        *  why clients must get responsibility on handling asynchronous
+        *  events.
+        */
+       if (!sync) {
+               TDM_WRN("Framebuffer back end does not support asynchronous vblank");
+               return TDM_ERROR_NONE;
+       }
+
+       fbdev_data = fbdev_output->fbdev_data;
+
+       ret = ioctl(fbdev_data->fbdev_fd, FBIO_WAITFORVSYNC, &crtc);
+       if (ret < 0) {
+               TDM_ERR("FBIO_WAITFORVSYNC ioctl failed, errno=%d", errno);
+               return TDM_ERROR_OPERATION_FAILED;
+       }
+
+       /*
+        * Up fake flag to simulate vsync event
+        */
+       fbdev_output->is_vblank = UP;
+       fbdev_output->user_data = user_data;
+
+       return TDM_ERROR_NONE;
+}
+
+tdm_error
+fbdev_output_set_vblank_handler(tdm_output *output, tdm_output_vblank_handler func)
+{
+       tdm_fbdev_output_data *fbdev_output = (tdm_fbdev_output_data *) output;
+
+       RETURN_VAL_IF_FAIL(fbdev_output, TDM_ERROR_INVALID_PARAMETER);
+       RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
+
+       fbdev_output->vblank_func = func;
+
+       return TDM_ERROR_NONE;
+}
+
+tdm_error
+fbdev_output_commit(tdm_output *output, int sync, void *user_data)
+{
+       tdm_fbdev_output_data *fbdev_output = (tdm_fbdev_output_data *) output;
+       tdm_fbdev_layer_data *fbdev_layer;
+       tdm_fbdev_display_buffer *display_buffer;
+       tbm_bo bo;
+       tbm_bo_handle bo_handle;
+
+       RETURN_VAL_IF_FAIL(fbdev_output, TDM_ERROR_INVALID_PARAMETER);
+
+       fbdev_layer = fbdev_output->fbdev_layer;
+
+       if (!fbdev_layer->display_buffer_changed)
+               return TDM_ERROR_NONE;
+
+       fbdev_output->mode_changed = 0;
+       fbdev_layer->display_buffer_changed = 0;
+       fbdev_layer->info_changed = 0;
+
+       display_buffer = fbdev_layer->display_buffer;
+
+       bo = tbm_surface_internal_get_bo(display_buffer->buffer, 0);
+       if (!bo) {
+               TDM_ERR("get bo fail");
+               return TDM_ERROR_OPERATION_FAILED;
+       }
+
+       bo_handle = tbm_bo_map(bo, TBM_DEVICE_CPU, TBM_OPTION_READ);
+       if (!bo_handle.ptr) {
+               TDM_ERR("map bo fail");
+               return TDM_ERROR_OPERATION_FAILED;
+       }
+
+       /*
+        * Display buffer's content to screen
+        */
+       memcpy(fbdev_output->mem, bo_handle.ptr, tbm_bo_size(bo) * sizeof(char));
+
+       tbm_bo_unmap(bo);
+
+       if (fbdev_output->commit_func) {
+               TDM_ERR("trace");
+               fbdev_output->commit_func((tdm_output *) output, fbdev_output->sequence++, 0, 0, user_data);
+       }
+
+       return TDM_ERROR_NONE;
+}
+
+tdm_error
+fbdev_output_set_commit_handler(tdm_output *output, tdm_output_commit_handler func)
+{
+       tdm_fbdev_output_data *fbdev_output = (tdm_fbdev_output_data *) output;
+
+       RETURN_VAL_IF_FAIL(fbdev_output, TDM_ERROR_INVALID_PARAMETER);
+       RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
+
+       fbdev_output->commit_func = func;
+
+       return TDM_ERROR_NONE;
+}
+
+tdm_error
+fbdev_output_set_dpms(tdm_output *output, tdm_output_dpms dpms_value)
+{
+       tdm_fbdev_output_data *fbdev_output = (tdm_fbdev_output_data *) output;
+       tdm_fbdev_data *fbdev_data;
+       int fbmode = 0;
+       int ret;
+
+       RETURN_VAL_IF_FAIL(fbdev_output, TDM_ERROR_INVALID_PARAMETER);
+
+       /*
+        * Bypass context switching overhead
+        */
+       if (fbdev_output->dpms_value == dpms_value)
+               return TDM_ERROR_NONE;
+
+       fbdev_data = fbdev_output->fbdev_data;
+
+       switch (dpms_value) {
+       case TDM_OUTPUT_DPMS_ON:
+               fbmode = FB_BLANK_UNBLANK;
+               break;
+
+       case TDM_OUTPUT_DPMS_OFF:
+               fbmode = FB_BLANK_POWERDOWN;
+               break;
+
+       case TDM_OUTPUT_DPMS_STANDBY:
+               fbmode = FB_BLANK_VSYNC_SUSPEND;
+               break;
+
+       case TDM_OUTPUT_DPMS_SUSPEND:
+               fbmode = FB_BLANK_HSYNC_SUSPEND;
+               break;
+
+       default:
+               NEVER_GET_HERE();
+               break;
+       }
+
+       ret = ioctl(fbdev_data->fbdev_fd, FBIOBLANK, &fbmode);
+       if (ret < 0) {
+               TDM_ERR("FBIOBLANK ioctl failed, errno=%d", errno);
+               return TDM_ERROR_OPERATION_FAILED;
+       }
+
+       /*
+        * TODO: framebuffer have to be reinitialized again, Maybe
+        */
+
+       fbdev_output->dpms_value = dpms_value;
+       fbmode = 0;
+
+       return TDM_ERROR_NONE;
+}
+
+tdm_error
+fbdev_output_get_dpms(tdm_output *output, tdm_output_dpms *dpms_value)
+{
+       tdm_fbdev_output_data *fbdev_output = (tdm_fbdev_output_data *) output;
+
+       RETURN_VAL_IF_FAIL(fbdev_output, TDM_ERROR_INVALID_PARAMETER);
+       RETURN_VAL_IF_FAIL(dpms_value, TDM_ERROR_INVALID_PARAMETER);
+
+       *dpms_value = fbdev_output->dpms_value;
+
+       return TDM_ERROR_NONE;
+}
+
+tdm_error
+fbdev_output_set_mode(tdm_output *output, const tdm_output_mode *mode)
+{
+       tdm_fbdev_output_data *fbdev_output = (tdm_fbdev_output_data *) output;
+
+       RETURN_VAL_IF_FAIL(fbdev_output, TDM_ERROR_INVALID_PARAMETER);
+       RETURN_VAL_IF_FAIL(mode, TDM_ERROR_INVALID_PARAMETER);
+
+       /*
+        * We currently support only one mode
+        */
+       if (fbdev_output->count_modes == 1)
+               return TDM_ERROR_NONE;
+
+       /*
+        * TODO: Implement mode switching
+        */
+       fbdev_output->mode_changed = 0;
+
+       return TDM_ERROR_NONE;
+}
+
+tdm_error
+fbdev_output_get_mode(tdm_output *output, const tdm_output_mode **mode)
+{
+       tdm_fbdev_output_data *fbdev_output = (tdm_fbdev_output_data *) output;
+
+       RETURN_VAL_IF_FAIL(fbdev_output, TDM_ERROR_INVALID_PARAMETER);
+       RETURN_VAL_IF_FAIL(mode, TDM_ERROR_INVALID_PARAMETER);
+
+       *mode = fbdev_output->current_mode;
+
+       return TDM_ERROR_NONE;
+}
+
+tdm_error
+fbdev_layer_get_capability(tdm_layer *layer, tdm_caps_layer *caps)
+{
+       tdm_fbdev_layer_data *fbdev_layer = (tdm_fbdev_layer_data *) layer;
+       tdm_error ret;
+       int i;
+
+       RETURN_VAL_IF_FAIL(fbdev_layer, TDM_ERROR_INVALID_PARAMETER);
+       RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER);
+
+       memset(caps, 0, sizeof(tdm_caps_layer));
+
+       caps->capabilities = fbdev_layer->capabilities;
+
+       /*
+        * Make our single GRAPHIC layer the lowest one aka "Prime"
+        */
+       caps->zpos = 0;
+
+       caps->format_count = sizeof(supported_formats) / sizeof(supported_formats[0]);
+       caps->formats = calloc(caps->format_count, sizeof(tbm_format));
+       if (!caps->formats) {
+               ret = TDM_ERROR_OUT_OF_MEMORY;
+               TDM_ERR("alloc failed\n");
+               goto failed_get;
+       }
+
+       for (i = 0; i < caps->format_count; i++)
+               caps->formats[i] = supported_formats[i];
+
+       /*
+        * Framebuffer does not have layer properties
+        */
+       caps->prop_count = 0;
+       caps->props = NULL;
+
+       return TDM_ERROR_NONE;
+
+failed_get:
+
+       memset(caps, 0, sizeof(tdm_caps_layer));
+       return ret;
+}
+
+tdm_error
+fbdev_layer_set_property(tdm_layer *layer, unsigned int id, tdm_value value)
+{
+       /*
+        * Framebuffer does not have layer properties
+        */
+       return TDM_ERROR_NONE;
+}
+
+tdm_error
+fbdev_layer_get_property(tdm_layer *layer, unsigned int id, tdm_value *value)
+{
+       /*
+        * Framebuffer does not have layer properties
+        */
+       return TDM_ERROR_NONE;
+}
+
+tdm_error
+fbdev_layer_set_info(tdm_layer *layer, tdm_info_layer *info)
+{
+       tdm_fbdev_layer_data *fbdev_layer = (tdm_fbdev_layer_data *) layer;
+
+       RETURN_VAL_IF_FAIL(fbdev_layer, TDM_ERROR_INVALID_PARAMETER);
+       RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER);
+
+       fbdev_layer->info = *info;
+
+       /*
+        * We do not use info in this backend, therefore just ignore
+        *  info's changing
+        */
+       fbdev_layer->info_changed = 0;
+
+       return TDM_ERROR_NONE;
+}
+
+tdm_error
+fbdev_layer_get_info(tdm_layer *layer, tdm_info_layer *info)
+{
+       tdm_fbdev_layer_data *fbdev_layer = (tdm_fbdev_layer_data *) layer;
+
+       RETURN_VAL_IF_FAIL(fbdev_layer, TDM_ERROR_INVALID_PARAMETER);
+       RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER);
+
+       *info = fbdev_layer->info;
+
+       return TDM_ERROR_NONE;
+}
+
+tdm_error
+fbdev_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer)
+{
+       tdm_fbdev_layer_data *fbdev_layer = (tdm_fbdev_layer_data *) layer;
+       tdm_fbdev_display_buffer *display_buffer;
+       tdm_fbdev_data *fbdev_data;
+       tdm_error err = TDM_ERROR_NONE;
+
+       RETURN_VAL_IF_FAIL(fbdev_layer, TDM_ERROR_INVALID_PARAMETER);
+       RETURN_VAL_IF_FAIL(buffer, TDM_ERROR_INVALID_PARAMETER);
+
+       if (tbm_surface_internal_get_num_bos(buffer) > 1) {
+               TDM_ERR("Framebuffer backend does not support surfaces with more than one bos");
+               return TDM_ERROR_INVALID_PARAMETER;
+       }
+
+       fbdev_data = fbdev_layer->fbdev_data;
+
+       display_buffer = _tdm_fbdev_display_find_buffer(fbdev_data, buffer);
+       if (!display_buffer) {
+               display_buffer = calloc(1, sizeof(tdm_fbdev_display_buffer));
+               if (display_buffer == NULL) {
+                       TDM_ERR("alloc failed");
+                       return TDM_ERROR_OUT_OF_MEMORY;
+               }
+
+               display_buffer->buffer = buffer;
+               display_buffer->width = tbm_surface_get_width(buffer);
+               display_buffer->height = tbm_surface_get_height(buffer);
+
+               err = tdm_buffer_add_destroy_handler(buffer, _tdm_fbdev_display_cb_destroy_buffer, fbdev_data);
+               if (err != TDM_ERROR_NONE) {
+                       TDM_ERR("add destroy handler fail");
+                       free(display_buffer);
+                       return TDM_ERROR_OPERATION_FAILED;
+               }
+
+               LIST_ADDTAIL(&display_buffer->link, &fbdev_data->buffer_list);
+       }
+
+       fbdev_layer->display_buffer = display_buffer;
+       fbdev_layer->display_buffer_changed = 1;
+
+       return TDM_ERROR_NONE;
+}
+
+tdm_error
+fbdev_layer_unset_buffer(tdm_layer *layer)
+{
+       tdm_fbdev_layer_data *fbdev_layer = (tdm_fbdev_layer_data *) layer;
+
+       RETURN_VAL_IF_FAIL(fbdev_layer, TDM_ERROR_INVALID_PARAMETER);
+
+       fbdev_layer->display_buffer = NULL;
+       fbdev_layer->display_buffer_changed = 1;
+
+       return TDM_ERROR_NONE;
+}
diff --git a/src/tdm_fbdev.c b/src/tdm_fbdev.c
deleted file mode 100644 (file)
index 33ef4ef..0000000
+++ /dev/null
@@ -1,284 +0,0 @@
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "tdm_fbdev.h"
-#include <tdm_helper.h>
-
-#define TDM_FBDEV_NAME "fbdev"
-
-static tdm_fbdev_data *fbdev_data;
-
-static int
-_tdm_fbdev_open_fbdev(void)
-{
-       const char *name = "/dev/fb0";
-       int fd = -1;
-
-       fd = open(name, O_RDWR);
-       if (fd < 0) {
-               TDM_ERR("Cannot open fbdev device.. search by udev");
-               goto close;
-       }
-
-       /*
-        * TODO: If we failed directly to open framebuffer device
-        * we would try to open it through udev
-        */
-
-close:
-
-       return fd;
-}
-
-static tdm_error
-_tdm_fbdev_init_internal(void)
-{
-       struct fb_fix_screeninfo *finfo = calloc(1, sizeof(struct fb_fix_screeninfo));
-       struct fb_var_screeninfo *vinfo = calloc(1, sizeof(struct fb_var_screeninfo));
-       int ret = -1;
-
-       ret = ioctl(fbdev_data->fbdev_fd, FBIOGET_VSCREENINFO, vinfo);
-       if (ret < 0) {
-               TDM_ERR("FBIOGET_VSCREENINFO ioctl failed errno=%d", errno);
-               goto close_1;
-       }
-
-       vinfo->reserved[0] = 0;
-       vinfo->reserved[1] = 0;
-       vinfo->reserved[2] = 0;
-       vinfo->xoffset = 0;
-       vinfo->yoffset = 0;
-       vinfo->activate = FB_ACTIVATE_NOW;
-
-       /*
-        * Explicitly request 32 bits per pixel colors with corresponding
-        * red, blue and green color offsets and length of colors
-        */
-       vinfo->bits_per_pixel   = 32;
-       vinfo->red.offset               = 16;
-       vinfo->red.length               = 8;
-       vinfo->green.offset             = 8;
-       vinfo->green.length             = 8;
-       vinfo->blue.offset              = 0;
-       vinfo->blue.length              = 8;
-       vinfo->transp.offset    = 0;
-       vinfo->transp.length    = 0;
-
-       vinfo->yres_virtual = vinfo->yres * MAX_BUF;
-       ret = ioctl(fbdev_data->fbdev_fd, FBIOPAN_DISPLAY, vinfo);
-       if (ret < 0)
-               TDM_ERR("FBIOPAN_DISPLAY ioctl failed, errno=%d", errno);
-
-       ret = ioctl(fbdev_data->fbdev_fd, FBIOGET_FSCREENINFO, finfo);
-       if (ret < 0) {
-               TDM_ERR("FBIOGET_FSCREENINFO ioctl failed, errno=%d", errno);
-               goto close_1;
-       }
-
-       if (finfo->smem_len <= 0) {
-               TDM_ERR("Length of frame buffer mem less then 0");
-               goto close_1;
-       }
-
-       fbdev_data->vinfo = vinfo;
-       fbdev_data->finfo = finfo;
-
-       /*
-        * Output framebuffer's related information
-        */
-       TDM_INFO("\n"
-                       " VInfo\n"
-                       "   fb           = %d\n"
-                       "   xres         = %d px \n"
-                       "   yres         = %d px \n"
-                       "   xres_virtual = %d px \n"
-                       "   yres_virtual = %d px \n"
-                       "   bpp          = %d    \n"
-                       "   r            = %2u:%u\n"
-                       "   g            = %2u:%u\n"
-                       "   b            = %2u:%u\n"
-                       "   t            = %2u:%u\n"
-                       "   active       = %d    \n"
-                       "   width        = %d mm \n"
-                       "   height       = %d mm \n",
-                       fbdev_data->fbdev_fd,
-                       vinfo->xres,
-                       vinfo->yres,
-                       vinfo->xres_virtual,
-                       vinfo->yres_virtual,
-                       vinfo->bits_per_pixel,
-                       vinfo->red.offset, vinfo->red.length,
-                       vinfo->green.offset, vinfo->green.length,
-                       vinfo->blue.offset, vinfo->blue.length,
-                       vinfo->transp.offset, vinfo->transp.length,
-                       vinfo->activate,
-                       vinfo->width,
-                       vinfo->height);
-
-       TDM_INFO("\n"
-                       " FInfo\n"
-                       "   id          = %s\n"
-                       "   smem_len    = %d\n"
-                       "   line_length = %d\n",
-                       finfo->id,
-                       finfo->smem_len,
-                       finfo->line_length);
-
-       return TDM_ERROR_NONE;
-close_1:
-       ret = TDM_ERROR_OPERATION_FAILED;
-       return ret;
-}
-
-void
-tdm_fbdev_deinit(tdm_backend_data *bdata)
-{
-       if (fbdev_data != bdata)
-               return;
-
-       TDM_INFO("deinit");
-
-       close(fbdev_data->fbdev_fd);
-
-       tdm_fbdev_destroy_layer(fbdev_data);
-       tdm_fbdev_destroy_output(fbdev_data);
-
-       if (fbdev_data->vinfo)
-               free(fbdev_data->vinfo);
-
-       if (fbdev_data->finfo)
-               free(fbdev_data->finfo);
-
-       free(fbdev_data);
-       fbdev_data = NULL;
-}
-
-tdm_backend_data*
-tdm_fbdev_init(tdm_display *dpy, tdm_error *error)
-{
-       tdm_func_display fbdev_func_display;
-       tdm_func_output fbdev_func_output;
-       tdm_func_layer fbdev_func_layer;
-       tdm_error ret;
-
-       if (!dpy) {
-               TDM_ERR("display is null");
-               if (error)
-                       *error = TDM_ERROR_BAD_REQUEST;
-               return NULL;
-       }
-
-       if (fbdev_data) {
-               TDM_ERR("failed: init twice");
-               if (error)
-                       *error = TDM_ERROR_BAD_REQUEST;
-               return NULL;
-       }
-
-       fbdev_data = calloc(1, sizeof(struct _tdm_fbdev_data));
-       if (!fbdev_data) {
-               TDM_ERR("alloc failed");
-               if (error)
-                       *error = TDM_ERROR_OUT_OF_MEMORY;
-               return NULL;
-       }
-
-       LIST_INITHEAD(&fbdev_data->buffer_list);
-
-       memset(&fbdev_func_display, 0, sizeof(fbdev_func_display));
-       fbdev_func_display.display_get_capability = fbdev_display_get_capability;
-       fbdev_func_display.display_get_outputs = fbdev_display_get_outputs;
-       fbdev_func_display.display_get_fd = NULL;
-       fbdev_func_display.display_handle_events = NULL;
-
-       memset(&fbdev_func_output, 0, sizeof(fbdev_func_output));
-       fbdev_func_output.output_get_capability = fbdev_output_get_capability;
-       fbdev_func_output.output_get_layers = fbdev_output_get_layers;
-       fbdev_func_output.output_set_property = fbdev_output_set_property;
-       fbdev_func_output.output_get_property = fbdev_output_get_property;
-       fbdev_func_output.output_wait_vblank = fbdev_output_wait_vblank;
-       fbdev_func_output.output_set_vblank_handler = fbdev_output_set_vblank_handler;
-       fbdev_func_output.output_commit = fbdev_output_commit;
-       fbdev_func_output.output_set_commit_handler = fbdev_output_set_commit_handler;
-       fbdev_func_output.output_set_dpms = fbdev_output_set_dpms;
-       fbdev_func_output.output_get_dpms = fbdev_output_get_dpms;
-       fbdev_func_output.output_set_mode = fbdev_output_set_mode;
-       fbdev_func_output.output_get_mode = fbdev_output_get_mode;
-
-       memset(&fbdev_func_layer, 0, sizeof(fbdev_func_layer));
-       fbdev_func_layer.layer_get_capability = fbdev_layer_get_capability;
-       fbdev_func_layer.layer_set_property = fbdev_layer_set_property;
-       fbdev_func_layer.layer_get_property = fbdev_layer_get_property;
-       fbdev_func_layer.layer_set_info = fbdev_layer_set_info;
-       fbdev_func_layer.layer_get_info = fbdev_layer_get_info;
-       fbdev_func_layer.layer_set_buffer = fbdev_layer_set_buffer;
-       fbdev_func_layer.layer_unset_buffer = fbdev_layer_unset_buffer;
-
-       ret = tdm_backend_register_func_display(dpy, &fbdev_func_display);
-       if (ret != TDM_ERROR_NONE)
-               goto failed;
-
-       ret = tdm_backend_register_func_output(dpy, &fbdev_func_output);
-       if (ret != TDM_ERROR_NONE)
-               goto failed;
-
-       ret = tdm_backend_register_func_layer(dpy, &fbdev_func_layer);
-       if (ret != TDM_ERROR_NONE)
-               goto failed;
-
-       fbdev_data->dpy = dpy;
-
-       fbdev_data->fbdev_fd = _tdm_fbdev_open_fbdev();
-       if (fbdev_data->fbdev_fd < 0) {
-               ret = TDM_ERROR_OPERATION_FAILED;
-               goto failed;
-       }
-
-       ret = _tdm_fbdev_init_internal();
-       if (ret != TDM_ERROR_NONE) {
-               TDM_INFO("init of framebuffer failed");
-               goto failed;
-       }
-
-       ret = tdm_fbdev_creat_output(fbdev_data);
-       if (ret != TDM_ERROR_NONE) {
-               TDM_INFO("init of output failed");
-               goto failed_2;
-       }
-
-       ret = tdm_fbdev_creat_layer(fbdev_data);
-       if (ret != TDM_ERROR_NONE) {
-               TDM_INFO("init of output failed");
-               goto failed_3;
-       }
-
-       TDM_INFO("init success!");
-
-       if (error)
-               *error = TDM_ERROR_NONE;
-
-       return (tdm_backend_data*) fbdev_data;
-
-failed_3:
-        tdm_fbdev_destroy_layer(fbdev_data);
-failed_2:
-       tdm_fbdev_destroy_output(fbdev_data);
-
-failed:
-       if (error)
-               *error = ret;
-
-       tdm_fbdev_deinit(fbdev_data);
-
-       TDM_ERR("init failed!");
-       return NULL;
-}
-
-tdm_backend_module tdm_backend_module_data = {
-       "fbdev",
-       "Samsung",
-       TDM_BACKEND_SET_ABI_VERSION(1, 1),
-       tdm_fbdev_init,
-       tdm_fbdev_deinit
-};
diff --git a/src/tdm_fbdev.h b/src/tdm_fbdev.h
deleted file mode 100644 (file)
index bc66fb0..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-#ifndef _TDM_fbdev_H_
-#define _TDM_fbdev_H_
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <pthread.h>
-#include <errno.h>
-#include <unistd.h>
-#include <limits.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-#include <fcntl.h>
-
-#include <linux/fb.h>
-
-#include <tbm_surface.h>
-#include <tbm_surface_internal.h>
-#include <tdm_backend.h>
-#include <tdm_log.h>
-#include <tdm_list.h>
-
-#define MAX_BUF 1
-
-/* fbdev backend functions (display) */
-tdm_error              fbdev_display_get_capability(tdm_backend_data *bdata, tdm_caps_display *caps);
-tdm_output**   fbdev_display_get_outputs(tdm_backend_data *bdata, int *count, tdm_error *error);
-tdm_error              fbdev_display_get_fd(tdm_backend_data *bdata, int *fd);
-tdm_error              fbdev_display_handle_events(tdm_backend_data *bdata);
-tdm_pp*                        fbdev_display_create_pp(tdm_backend_data *bdata, tdm_error *error);
-tdm_error              fbdev_output_get_capability(tdm_output *output, tdm_caps_output *caps);
-tdm_layer**            fbdev_output_get_layers(tdm_output *output, int *count, tdm_error *error);
-tdm_error              fbdev_output_set_property(tdm_output *output, unsigned int id, tdm_value value);
-tdm_error              fbdev_output_get_property(tdm_output *output, unsigned int id, tdm_value *value);
-tdm_error              fbdev_output_wait_vblank(tdm_output *output, int interval, int sync, void *user_data);
-tdm_error              fbdev_output_set_vblank_handler(tdm_output *output, tdm_output_vblank_handler func);
-tdm_error              fbdev_output_commit(tdm_output *output, int sync, void *user_data);
-tdm_error              fbdev_output_set_commit_handler(tdm_output *output, tdm_output_commit_handler func);
-tdm_error              fbdev_output_set_dpms(tdm_output *output, tdm_output_dpms dpms_value);
-tdm_error              fbdev_output_get_dpms(tdm_output *output, tdm_output_dpms *dpms_value);
-tdm_error              fbdev_output_set_mode(tdm_output *output, const tdm_output_mode *mode);
-tdm_error              fbdev_output_get_mode(tdm_output *output, const tdm_output_mode **mode);
-tdm_error              fbdev_layer_get_capability(tdm_layer *layer, tdm_caps_layer *caps);
-tdm_error              fbdev_layer_set_property(tdm_layer *layer, unsigned int id, tdm_value value);
-tdm_error              fbdev_layer_get_property(tdm_layer *layer, unsigned int id, tdm_value *value);
-tdm_error              fbdev_layer_set_info(tdm_layer *layer, tdm_info_layer *info);
-tdm_error              fbdev_layer_get_info(tdm_layer *layer, tdm_info_layer *info);
-tdm_error              fbdev_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer);
-tdm_error              fbdev_layer_unset_buffer(tdm_layer *layer);
-
-/* Framebuffer moudel's internal macros, functions, structures */
-#define NEVER_GET_HERE() TDM_ERR("** NEVER GET HERE **")
-
-#define RETURN_VAL_IF_FAIL(cond, val) {\
-       if (!(cond)) {\
-               TDM_ERR("'%s' failed", #cond);\
-               return val;\
-       }       \
-}
-
-typedef struct _tdm_fbdev_output_data tdm_fbdev_output_data;
-typedef struct _tdm_fbdev_layer_data tdm_fbdev_layer_data;
-typedef struct _tdm_fbdev_display_buffer tdm_fbdev_display_buffer;
-
-typedef struct _tdm_fbdev_data {
-       tdm_fbdev_output_data *fbdev_output;
-
-       int fbdev_fd;
-
-       tdm_display *dpy;
-
-       struct fb_fix_screeninfo *finfo;
-       struct fb_var_screeninfo *vinfo;
-
-       struct list_head buffer_list;
-} tdm_fbdev_data;
-
-struct _tdm_fbdev_output_data {
-       tdm_fbdev_data *fbdev_data;
-       tdm_fbdev_layer_data *fbdev_layer;
-
-       uint32_t width;
-       uint32_t height;
-       uint32_t pitch;
-       uint32_t bpp;
-       size_t size;
-       uint32_t max_width;
-       uint32_t max_height;
-
-       /*
-        * Poinetr to Framebuffers's mapped memory
-        */
-       void *mem;
-
-       int count_modes;
-       tdm_output_mode *output_modes;
-       int mode_changed;
-
-       /*
-        * Frambuffer device back end currently support only one mode
-        */
-       const tdm_output_mode *current_mode;
-
-       tdm_output_type connector_type;
-       tdm_output_conn_status status;
-       unsigned int connector_type_id;
-
-       tdm_output_dpms dpms_value;
-
-       /*
-        * Event handlers
-        */
-       tdm_output_vblank_handler vblank_func;
-       tdm_output_commit_handler commit_func;
-
-       void *user_data;
-
-       /*
-        * Fake flags are used to simulate event-operated back end. Since tdm
-        *  library assumes its back ends to be event-operated and Framebuffer
-        *  device is not event-operated we have to make fake events
-        */
-       int is_vblank;
-       int is_commit;
-
-       int sequence;
-
-};
-
-struct _tdm_fbdev_layer_data {
-       tdm_fbdev_data *fbdev_data;
-       tdm_fbdev_output_data *fbdev_output;
-
-       tdm_fbdev_display_buffer *display_buffer;
-       int display_buffer_changed;
-
-       tdm_layer_capability capabilities;
-       tdm_info_layer info;
-       int info_changed;
-};
-
-enum {
-       DOWN = 0,
-       UP,
-};
-
-struct _tdm_fbdev_display_buffer {
-       struct list_head link;
-
-       int width;
-       int height;
-
-       tbm_surface_h buffer;
-};
-
-tdm_error      tdm_fbdev_creat_output(tdm_fbdev_data *fbdev_data);
-void           tdm_fbdev_destroy_output(tdm_fbdev_data *fbdev_data);
-
-tdm_error      tdm_fbdev_creat_layer(tdm_fbdev_data *fbdev_data);
-void           tdm_fbdev_destroy_layer(tdm_fbdev_data *fbdev_data);
-
-#endif /* _TDM_fbdev_H_ */
diff --git a/src/tdm_fbdev_display.c b/src/tdm_fbdev_display.c
deleted file mode 100644 (file)
index 63ee64e..0000000
+++ /dev/null
@@ -1,834 +0,0 @@
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <tdm_helper.h>
-#include <stdint.h>
-#include "tdm_fbdev.h"
-
-#include <xf86drm.h>
-#include <libudev.h>
-
-/*
- * Framebuffer device supported formats
- */
-static tbm_format supported_formats[] = {
-       /*
-        * TODO: add support of 16 bit formats
-        */
-       TBM_FORMAT_ARGB8888,
-       TBM_FORMAT_ABGR8888,
-       TBM_FORMAT_RGBA8888,
-       TBM_FORMAT_BGRA8888,
-};
-
-static tdm_fbdev_display_buffer*
-_tdm_fbdev_display_find_buffer(tdm_fbdev_data *fbdev_data, tbm_surface_h buffer)
-{
-       tdm_fbdev_display_buffer *display_buffer = NULL;
-
-       LIST_FOR_EACH_ENTRY(display_buffer, &fbdev_data->buffer_list, link)
-       {
-               if (display_buffer->buffer == buffer)
-                       return display_buffer;
-       }
-
-       return NULL;
-}
-
-static void
-_tdm_fbdev_display_cb_destroy_buffer(tbm_surface_h buffer, void *user_data)
-{
-       tdm_fbdev_data *fbdev_data;
-       tdm_fbdev_display_buffer *display_buffer;
-
-       if (!user_data) {
-               TDM_ERR("no user_data");
-               return;
-       }
-       if (!buffer) {
-               TDM_ERR("no buffer");
-               return;
-       }
-
-       fbdev_data = (tdm_fbdev_data *) user_data;
-
-       display_buffer = _tdm_fbdev_display_find_buffer(fbdev_data, buffer);
-       if (!display_buffer) {
-               TDM_ERR("no display_buffer");
-               return;
-       }
-
-       LIST_DEL(&display_buffer->link);
-
-       free(display_buffer);
-}
-
-
-static inline uint32_t
-_get_refresh(struct fb_var_screeninfo *timing)
-{
-       uint32_t pixclock, hfreq, htotal, vtotal;
-
-       pixclock = PICOS2KHZ(timing->pixclock) * 1000;
-
-       htotal = timing->xres + timing->right_margin + timing->hsync_len + timing->left_margin;
-       vtotal = timing->yres + timing->lower_margin + timing->vsync_len + timing->upper_margin;
-
-       if (timing->vmode & FB_VMODE_INTERLACED)
-               vtotal /= 2;
-       if (timing->vmode & FB_VMODE_DOUBLE)
-               vtotal *= 2;
-
-       hfreq = pixclock / htotal;
-       return hfreq / vtotal;
-}
-
-/*
- * Convert fb_var_screeninfo to tdm_output_mode
- */
-static inline void
-_tdm_fbdev_display_to_tdm_mode(struct fb_var_screeninfo *timing, tdm_output_mode *mode)
-{
-
-       if (!timing->pixclock)
-               return;
-
-       mode->clock = timing->pixclock / 1000;
-       mode->vrefresh = _get_refresh(timing);
-       mode->hdisplay = timing->xres;
-       mode->hsync_start = mode->hdisplay + timing->right_margin;
-       mode->hsync_end = mode->hsync_start + timing->hsync_len;
-       mode->htotal = mode->hsync_end + timing->left_margin;
-
-       mode->vdisplay = timing->yres;
-       mode->vsync_start = mode->vdisplay + timing->lower_margin;
-       mode->vsync_end = mode->vsync_start + timing->vsync_len;
-       mode->vtotal = mode->vsync_end + timing->upper_margin;
-
-       int interlaced = !!(timing->vmode & FB_VMODE_INTERLACED);
-       snprintf(mode->name, TDM_NAME_LEN, "%dx%d%s", mode->hdisplay, mode->vdisplay, interlaced ? "i" : "");
-}
-
-tdm_error
-tdm_fbdev_creat_output(tdm_fbdev_data *fbdev_data)
-{
-       tdm_fbdev_output_data *output = NULL;
-       size_t size;
-       int i = 0;
-
-       output = calloc(1, sizeof(tdm_fbdev_output_data));
-       if (output == NULL) {
-               TDM_ERR("alloc output failed");
-               return TDM_ERROR_OUT_OF_MEMORY;
-       }
-
-       /*
-        * TODO: Size of framebuffer must be aligned to system page size before
-        *  it is mapped
-        */
-       size = fbdev_data->vinfo->xres * fbdev_data->vinfo->yres * fbdev_data->vinfo->bits_per_pixel / 8 * MAX_BUF;
-
-       TDM_INFO("\n" "MMaped size: %zu\n", size);
-
-       output->mem = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fbdev_data->fbdev_fd, 0);
-       if (output->mem == MAP_FAILED) {
-               TDM_ERR("MMap framebuffer failed, errno=%d", errno);
-               return TDM_ERROR_OPERATION_FAILED;
-       }
-
-       memset(output->mem, 0, size);
-
-       output->width = fbdev_data->vinfo->xres;
-       output->height = fbdev_data->vinfo->yres;
-       output->pitch = fbdev_data->vinfo->width;
-       output->bpp = fbdev_data->vinfo->bits_per_pixel;
-       output->size = size;
-       output->max_width = fbdev_data->vinfo->xres_virtual;
-       output->max_height = fbdev_data->vinfo->yres_virtual;
-
-       output->status = TDM_OUTPUT_CONN_STATUS_CONNECTED;
-       output->connector_type = TDM_OUTPUT_TYPE_LVDS;
-
-       output->is_vblank = DOWN;
-       output->is_commit = DOWN;
-       output->sequence = 1;
-
-       /*
-        * TODO: connector_type_id field relates to libdrm connector which framebuffer
-        *  does not know. It have to be checked whether softaware above us use this
-        *  field for its purposes.
-        */
-       output->connector_type_id = 1;
-
-       output->count_modes = 1;
-       output->output_modes = calloc(output->count_modes, sizeof(tdm_output_mode));
-       if (!output->output_modes) {
-               TDM_ERR("failed: alloc memory");
-               return TDM_ERROR_OUT_OF_MEMORY;
-       }
-
-       for (i = 0; i < output->count_modes; i++) {
-               _tdm_fbdev_display_to_tdm_mode(fbdev_data->vinfo, &output->output_modes[i]);
-
-               sprintf(output->output_modes[i].name, "%dx%d", fbdev_data->vinfo->xres, fbdev_data->vinfo->yres);
-       }
-
-       /*
-        * We currently support only one mode
-        */
-       if (output->count_modes == 1) {
-               output->current_mode = &output->output_modes[0];
-               output->status = TDM_OUTPUT_CONN_STATUS_MODE_SETTED;
-       }
-
-       output->fbdev_data = fbdev_data;
-       fbdev_data->fbdev_output = output;
-
-       return TDM_ERROR_NONE;
-}
-
-void
-tdm_fbdev_destroy_output(tdm_fbdev_data *fbdev_data)
-{
-       tdm_fbdev_output_data *fbdev_output = fbdev_data->fbdev_output;
-
-       if (fbdev_output == NULL)
-               goto close;
-
-       if (fbdev_output->mem == NULL)
-               goto close_2;
-
-       munmap(fbdev_output->mem, fbdev_output->size);
-
-       if (fbdev_output->output_modes == NULL)
-               goto close_2;
-
-       free(fbdev_output->output_modes);
-
-close_2:
-       free(fbdev_output);
-close:
-       return;
-}
-
-tdm_error
-tdm_fbdev_creat_layer(tdm_fbdev_data *fbdev_data)
-{
-       tdm_fbdev_layer_data *layer;
-       tdm_fbdev_output_data *fbdev_output = fbdev_data->fbdev_output;
-
-       /*
-        * Framebuffer does not support layer, therefore create only
-        *  one layer by libtdm's demand;
-        */
-       layer = calloc(1, sizeof(tdm_fbdev_layer_data));
-       if (layer == NULL) {
-               TDM_ERR("alloc output failed");
-               return TDM_ERROR_OUT_OF_MEMORY;
-       }
-
-       layer->capabilities = TDM_LAYER_CAPABILITY_PRIMARY | TDM_LAYER_CAPABILITY_GRAPHIC;
-
-       layer->fbdev_data = fbdev_data;
-       layer->fbdev_output = fbdev_output;
-       fbdev_output->fbdev_layer = layer;
-
-       return TDM_ERROR_NONE;
-}
-
-void
-tdm_fbdev_destroy_layer(tdm_fbdev_data *fbdev_data)
-{
-       tdm_fbdev_output_data *fbdev_output = fbdev_data->fbdev_output;
-       tdm_fbdev_layer_data *layer = fbdev_output->fbdev_layer;
-
-       if (layer != NULL)
-               free(layer);
-}
-
-tdm_error
-fbdev_display_get_capability(tdm_backend_data *bdata, tdm_caps_display *caps)
-{
-       RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER);
-
-       /*
-        * Framebuffer does not support layer, therefore create only
-        *  one layer by libtdm's demand;
-        */
-       caps->max_layer_count = 1;
-
-       return TDM_ERROR_NONE;
-}
-
-tdm_output**
-fbdev_display_get_outputs(tdm_backend_data *bdata, int *count, tdm_error *error)
-{
-       tdm_fbdev_data *fbdev_data = bdata;
-       tdm_fbdev_output_data *fbdev_output = fbdev_data->fbdev_output;
-       tdm_output **outputs;
-       tdm_error ret;
-
-       RETURN_VAL_IF_FAIL(fbdev_data, NULL);
-       RETURN_VAL_IF_FAIL(count, NULL);
-
-       if (fbdev_output == NULL) {
-               ret = TDM_ERROR_NONE;
-               goto failed_get;
-       }
-
-       /*
-        * Since it is Framebuffer device there is only one output
-        */
-       *count = 1;
-
-       /* will be freed in frontend */
-       outputs = calloc(*count, sizeof(tdm_fbdev_output_data*));
-       if (!outputs) {
-               TDM_ERR("failed: alloc memory");
-               *count = 0;
-               ret = TDM_ERROR_OUT_OF_MEMORY;
-               goto failed_get;
-       }
-
-       outputs[0] = fbdev_output;
-
-       if (error)
-               *error = TDM_ERROR_NONE;
-
-       return outputs;
-
-failed_get:
-
-       if (error)
-               *error = ret;
-       return NULL;
-}
-
-tdm_error
-fbdev_display_handle_events(tdm_backend_data *bdata)
-{
-       tdm_fbdev_data *fbdev_data = (tdm_fbdev_data *) bdata;
-       void *user_data;
-       tdm_fbdev_output_data *fbdev_output;
-       unsigned int sequence = 0;
-       unsigned int tv_sec = 0;
-       unsigned int tv_usec = 0;
-
-       RETURN_VAL_IF_FAIL(fbdev_data, TDM_ERROR_INVALID_PARAMETER);
-
-       fbdev_output = fbdev_data->fbdev_output;
-       user_data = fbdev_output->user_data;
-
-       RETURN_VAL_IF_FAIL(user_data, TDM_ERROR_INVALID_PARAMETER);
-
-       /*
-        (tdm_output *output, unsigned int sequence,
-        unsigned int tv_sec, unsigned int tv_usec,
-        void *user_data);
-        */
-
-       /*
-        * Framebuffer does not produce events
-        * Fake flags are used to simulate event-operated back end. Since tdm
-        *  library assumes its back ends to be event-operated and Framebuffer
-        *  device is not event-operated we have to make fake events
-        */
-       if (fbdev_output->is_vblank && fbdev_output->vblank_func) {
-               fbdev_output->is_vblank = DOWN;
-
-               fbdev_output->vblank_func((tdm_output *) fbdev_data, sequence, tv_sec, tv_usec, user_data);
-       }
-
-       if (fbdev_output->is_commit && fbdev_output->commit_func) {
-               fbdev_output->is_commit = DOWN;
-
-               fbdev_output->commit_func((tdm_output *) fbdev_data, sequence, tv_sec, tv_usec, user_data);
-       }
-
-       return TDM_ERROR_NONE;
-}
-
-tdm_error
-fbdev_output_get_capability(tdm_output *output, tdm_caps_output *caps)
-{
-       tdm_fbdev_output_data *fbdev_output = (tdm_fbdev_output_data *) output;
-       tdm_fbdev_data *fbdev_data = NULL;
-       tdm_error ret;
-       int i = 0;
-
-       RETURN_VAL_IF_FAIL(fbdev_output, TDM_ERROR_INVALID_PARAMETER);
-       RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER);
-
-       memset(caps, 0, sizeof(tdm_caps_output));
-
-       fbdev_data = fbdev_output->fbdev_data;
-
-       snprintf(caps->maker, TDM_NAME_LEN, "unknown");
-       snprintf(caps->model, TDM_NAME_LEN, "unknown");
-       snprintf(caps->name, TDM_NAME_LEN, "unknown");
-
-       caps->status = fbdev_output->status;
-       caps->type = fbdev_output->connector_type;
-       caps->type_id = fbdev_output->connector_type_id;
-
-       caps->mode_count = fbdev_output->count_modes;
-       caps->modes = calloc(caps->mode_count, sizeof(tdm_output_mode));
-       if (!caps->modes) {
-               ret = TDM_ERROR_OUT_OF_MEMORY;
-               TDM_ERR("alloc failed\n");
-               goto failed_get;
-       }
-
-       for (i = 0; i < caps->mode_count; i++)
-               caps->modes[i] = fbdev_output->output_modes[i];
-
-       caps->mmWidth = fbdev_data->vinfo->width;
-       caps->mmHeight = fbdev_data->vinfo->height;
-       caps->subpixel = -1;
-
-       caps->min_w = fbdev_output->width;
-       caps->min_h = fbdev_output->height;
-       caps->max_w = fbdev_output->max_width;
-       caps->max_h = fbdev_output->max_height;
-       caps->preferred_align = -1;
-
-       /*
-        * Framebuffer does not have output properties
-        */
-       caps->prop_count = 0;
-       caps->props = NULL;
-
-       return TDM_ERROR_NONE;
-
-failed_get:
-       memset(caps, 0, sizeof(tdm_caps_output));
-       return ret;
-}
-
-tdm_layer**
-fbdev_output_get_layers(tdm_output *output, int *count, tdm_error *error)
-{
-       tdm_fbdev_output_data *fbdev_output = (tdm_fbdev_output_data *) output;
-       tdm_layer **layers;
-       tdm_error ret;
-
-       RETURN_VAL_IF_FAIL(fbdev_output, NULL);
-       RETURN_VAL_IF_FAIL(count, NULL);
-
-       /*
-        * Framebuffer does not support layer, therefore create only
-        *  one layer by libtdm's demand;
-        */
-       *count = 1;
-
-       layers = calloc(*count, sizeof(tdm_layer));
-       if (layers == NULL) {
-               TDM_ERR("failed: alloc memory");
-               *count = 0;
-               ret = TDM_ERROR_OUT_OF_MEMORY;
-               goto failed_get;
-       }
-
-       layers[0] = fbdev_output->fbdev_layer;
-
-       if (error)
-               *error = TDM_ERROR_NONE;
-
-       return layers;
-
-failed_get:
-
-       if (error)
-               *error = ret;
-
-       return NULL;
-}
-
-tdm_error
-fbdev_output_set_property(tdm_output *output, unsigned int id, tdm_value value)
-{
-       /*
-        * Framebuffer does not have output properties
-        */
-       return TDM_ERROR_NONE;
-}
-
-tdm_error
-fbdev_output_get_property(tdm_output *output, unsigned int id, tdm_value *value)
-{
-       /*
-        * Framebuffer does not have output properties
-        */
-       return TDM_ERROR_NONE;
-}
-
-tdm_error
-fbdev_output_wait_vblank(tdm_output *output, int interval, int sync, void *user_data)
-{
-       tdm_fbdev_output_data *fbdev_output = (tdm_fbdev_output_data *) output;
-       tdm_fbdev_data *fbdev_data;
-
-       int crtc = 0;
-       int ret;
-
-       RETURN_VAL_IF_FAIL(fbdev_output, TDM_ERROR_INVALID_PARAMETER);
-
-       /*
-        * Frame buffer device does not support asynchronous events, that is
-        *  why clients must get responsibility on handling asynchronous
-        *  events.
-        */
-       if (!sync) {
-               TDM_WRN("Framebuffer back end does not support asynchronous vblank");
-               return TDM_ERROR_NONE;
-       }
-
-       fbdev_data = fbdev_output->fbdev_data;
-
-       ret = ioctl(fbdev_data->fbdev_fd, FBIO_WAITFORVSYNC, &crtc);
-       if (ret < 0) {
-               TDM_ERR("FBIO_WAITFORVSYNC ioctl failed, errno=%d", errno);
-               return TDM_ERROR_OPERATION_FAILED;
-       }
-
-       /*
-        * Up fake flag to simulate vsync event
-        */
-       fbdev_output->is_vblank = UP;
-       fbdev_output->user_data = user_data;
-
-       return TDM_ERROR_NONE;
-}
-
-tdm_error
-fbdev_output_set_vblank_handler(tdm_output *output, tdm_output_vblank_handler func)
-{
-       tdm_fbdev_output_data *fbdev_output = (tdm_fbdev_output_data *) output;
-
-       RETURN_VAL_IF_FAIL(fbdev_output, TDM_ERROR_INVALID_PARAMETER);
-       RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
-
-       fbdev_output->vblank_func = func;
-
-       return TDM_ERROR_NONE;
-}
-
-tdm_error
-fbdev_output_commit(tdm_output *output, int sync, void *user_data)
-{
-       tdm_fbdev_output_data *fbdev_output = (tdm_fbdev_output_data *) output;
-       tdm_fbdev_layer_data *fbdev_layer;
-       tdm_fbdev_display_buffer *display_buffer;
-       tbm_bo bo;
-       tbm_bo_handle bo_handle;
-
-       RETURN_VAL_IF_FAIL(fbdev_output, TDM_ERROR_INVALID_PARAMETER);
-
-       fbdev_layer = fbdev_output->fbdev_layer;
-
-       if (!fbdev_layer->display_buffer_changed)
-               return TDM_ERROR_NONE;
-
-       fbdev_output->mode_changed = 0;
-       fbdev_layer->display_buffer_changed = 0;
-       fbdev_layer->info_changed = 0;
-
-       display_buffer = fbdev_layer->display_buffer;
-
-       bo = tbm_surface_internal_get_bo(display_buffer->buffer, 0);
-       if (!bo) {
-               TDM_ERR("get bo fail");
-               return TDM_ERROR_OPERATION_FAILED;
-       }
-
-       bo_handle = tbm_bo_map(bo, TBM_DEVICE_CPU, TBM_OPTION_READ);
-       if (!bo_handle.ptr) {
-               TDM_ERR("map bo fail");
-               return TDM_ERROR_OPERATION_FAILED;
-       }
-
-       /*
-        * Display buffer's content to screen
-        */
-       memcpy(fbdev_output->mem, bo_handle.ptr, tbm_bo_size(bo) * sizeof(char));
-
-       tbm_bo_unmap(bo);
-
-       if (fbdev_output->commit_func) {
-               TDM_ERR("trace");
-               fbdev_output->commit_func((tdm_output *) output, fbdev_output->sequence++, 0, 0, user_data);
-       }
-
-       return TDM_ERROR_NONE;
-}
-
-tdm_error
-fbdev_output_set_commit_handler(tdm_output *output, tdm_output_commit_handler func)
-{
-       tdm_fbdev_output_data *fbdev_output = (tdm_fbdev_output_data *) output;
-
-       RETURN_VAL_IF_FAIL(fbdev_output, TDM_ERROR_INVALID_PARAMETER);
-       RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
-
-       fbdev_output->commit_func = func;
-
-       return TDM_ERROR_NONE;
-}
-
-tdm_error
-fbdev_output_set_dpms(tdm_output *output, tdm_output_dpms dpms_value)
-{
-       tdm_fbdev_output_data *fbdev_output = (tdm_fbdev_output_data *) output;
-       tdm_fbdev_data *fbdev_data;
-       int fbmode = 0;
-       int ret;
-
-       RETURN_VAL_IF_FAIL(fbdev_output, TDM_ERROR_INVALID_PARAMETER);
-
-       /*
-        * Bypass context switching overhead
-        */
-       if (fbdev_output->dpms_value == dpms_value)
-               return TDM_ERROR_NONE;
-
-       fbdev_data = fbdev_output->fbdev_data;
-
-       switch (dpms_value) {
-       case TDM_OUTPUT_DPMS_ON:
-               fbmode = FB_BLANK_UNBLANK;
-               break;
-
-       case TDM_OUTPUT_DPMS_OFF:
-               fbmode = FB_BLANK_POWERDOWN;
-               break;
-
-       case TDM_OUTPUT_DPMS_STANDBY:
-               fbmode = FB_BLANK_VSYNC_SUSPEND;
-               break;
-
-       case TDM_OUTPUT_DPMS_SUSPEND:
-               fbmode = FB_BLANK_HSYNC_SUSPEND;
-               break;
-
-       default:
-               NEVER_GET_HERE();
-               break;
-       }
-
-       ret = ioctl(fbdev_data->fbdev_fd, FBIOBLANK, &fbmode);
-       if (ret < 0) {
-               TDM_ERR("FBIOBLANK ioctl failed, errno=%d", errno);
-               return TDM_ERROR_OPERATION_FAILED;
-       }
-
-       /*
-        * TODO: framebuffer have to be reinitialized again, Maybe
-        */
-
-       fbdev_output->dpms_value = dpms_value;
-       fbmode = 0;
-
-       return TDM_ERROR_NONE;
-}
-
-tdm_error
-fbdev_output_get_dpms(tdm_output *output, tdm_output_dpms *dpms_value)
-{
-       tdm_fbdev_output_data *fbdev_output = (tdm_fbdev_output_data *) output;
-
-       RETURN_VAL_IF_FAIL(fbdev_output, TDM_ERROR_INVALID_PARAMETER);
-       RETURN_VAL_IF_FAIL(dpms_value, TDM_ERROR_INVALID_PARAMETER);
-
-       *dpms_value = fbdev_output->dpms_value;
-
-       return TDM_ERROR_NONE;
-}
-
-tdm_error
-fbdev_output_set_mode(tdm_output *output, const tdm_output_mode *mode)
-{
-       tdm_fbdev_output_data *fbdev_output = (tdm_fbdev_output_data *) output;
-
-       RETURN_VAL_IF_FAIL(fbdev_output, TDM_ERROR_INVALID_PARAMETER);
-       RETURN_VAL_IF_FAIL(mode, TDM_ERROR_INVALID_PARAMETER);
-
-       /*
-        * We currently support only one mode
-        */
-       if (fbdev_output->count_modes == 1)
-               return TDM_ERROR_NONE;
-
-       /*
-        * TODO: Implement mode switching
-        */
-       fbdev_output->mode_changed = 0;
-
-       return TDM_ERROR_NONE;
-}
-
-tdm_error
-fbdev_output_get_mode(tdm_output *output, const tdm_output_mode **mode)
-{
-       tdm_fbdev_output_data *fbdev_output = (tdm_fbdev_output_data *) output;
-
-       RETURN_VAL_IF_FAIL(fbdev_output, TDM_ERROR_INVALID_PARAMETER);
-       RETURN_VAL_IF_FAIL(mode, TDM_ERROR_INVALID_PARAMETER);
-
-       *mode = fbdev_output->current_mode;
-
-       return TDM_ERROR_NONE;
-}
-
-tdm_error
-fbdev_layer_get_capability(tdm_layer *layer, tdm_caps_layer *caps)
-{
-       tdm_fbdev_layer_data *fbdev_layer = (tdm_fbdev_layer_data *) layer;
-       tdm_error ret;
-       int i;
-
-       RETURN_VAL_IF_FAIL(fbdev_layer, TDM_ERROR_INVALID_PARAMETER);
-       RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER);
-
-       memset(caps, 0, sizeof(tdm_caps_layer));
-
-       caps->capabilities = fbdev_layer->capabilities;
-
-       /*
-        * Make our single GRAPHIC layer the lowest one aka "Prime"
-        */
-       caps->zpos = 0;
-
-       caps->format_count = sizeof(supported_formats) / sizeof(supported_formats[0]);
-       caps->formats = calloc(caps->format_count, sizeof(tbm_format));
-       if (!caps->formats) {
-               ret = TDM_ERROR_OUT_OF_MEMORY;
-               TDM_ERR("alloc failed\n");
-               goto failed_get;
-       }
-
-       for (i = 0; i < caps->format_count; i++)
-               caps->formats[i] = supported_formats[i];
-
-       /*
-        * Framebuffer does not have layer properties
-        */
-       caps->prop_count = 0;
-       caps->props = NULL;
-
-       return TDM_ERROR_NONE;
-
-failed_get:
-
-       memset(caps, 0, sizeof(tdm_caps_layer));
-       return ret;
-}
-
-tdm_error
-fbdev_layer_set_property(tdm_layer *layer, unsigned int id, tdm_value value)
-{
-       /*
-        * Framebuffer does not have layer properties
-        */
-       return TDM_ERROR_NONE;
-}
-
-tdm_error
-fbdev_layer_get_property(tdm_layer *layer, unsigned int id, tdm_value *value)
-{
-       /*
-        * Framebuffer does not have layer properties
-        */
-       return TDM_ERROR_NONE;
-}
-
-tdm_error
-fbdev_layer_set_info(tdm_layer *layer, tdm_info_layer *info)
-{
-       tdm_fbdev_layer_data *fbdev_layer = (tdm_fbdev_layer_data *) layer;
-
-       RETURN_VAL_IF_FAIL(fbdev_layer, TDM_ERROR_INVALID_PARAMETER);
-       RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER);
-
-       fbdev_layer->info = *info;
-
-       /*
-        * We do not use info in this backend, therefore just ignore
-        *  info's changing
-        */
-       fbdev_layer->info_changed = 0;
-
-       return TDM_ERROR_NONE;
-}
-
-tdm_error
-fbdev_layer_get_info(tdm_layer *layer, tdm_info_layer *info)
-{
-       tdm_fbdev_layer_data *fbdev_layer = (tdm_fbdev_layer_data *) layer;
-
-       RETURN_VAL_IF_FAIL(fbdev_layer, TDM_ERROR_INVALID_PARAMETER);
-       RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER);
-
-       *info = fbdev_layer->info;
-
-       return TDM_ERROR_NONE;
-}
-
-tdm_error
-fbdev_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer)
-{
-       tdm_fbdev_layer_data *fbdev_layer = (tdm_fbdev_layer_data *) layer;
-       tdm_fbdev_display_buffer *display_buffer;
-       tdm_fbdev_data *fbdev_data;
-       tdm_error err = TDM_ERROR_NONE;
-
-       RETURN_VAL_IF_FAIL(fbdev_layer, TDM_ERROR_INVALID_PARAMETER);
-       RETURN_VAL_IF_FAIL(buffer, TDM_ERROR_INVALID_PARAMETER);
-
-       if (tbm_surface_internal_get_num_bos(buffer) > 1) {
-               TDM_ERR("Framebuffer backend does not support surfaces with more than one bos");
-               return TDM_ERROR_INVALID_PARAMETER;
-       }
-
-       fbdev_data = fbdev_layer->fbdev_data;
-
-       display_buffer = _tdm_fbdev_display_find_buffer(fbdev_data, buffer);
-       if (!display_buffer) {
-               display_buffer = calloc(1, sizeof(tdm_fbdev_display_buffer));
-               if (display_buffer == NULL) {
-                       TDM_ERR("alloc failed");
-                       return TDM_ERROR_OUT_OF_MEMORY;
-               }
-
-               display_buffer->buffer = buffer;
-               display_buffer->width = tbm_surface_get_width(buffer);
-               display_buffer->height = tbm_surface_get_height(buffer);
-
-               err = tdm_buffer_add_destroy_handler(buffer, _tdm_fbdev_display_cb_destroy_buffer, fbdev_data);
-               if (err != TDM_ERROR_NONE) {
-                       TDM_ERR("add destroy handler fail");
-                       free(display_buffer);
-                       return TDM_ERROR_OPERATION_FAILED;
-               }
-
-               LIST_ADDTAIL(&display_buffer->link, &fbdev_data->buffer_list);
-       }
-
-       fbdev_layer->display_buffer = display_buffer;
-       fbdev_layer->display_buffer_changed = 1;
-
-       return TDM_ERROR_NONE;
-}
-
-tdm_error
-fbdev_layer_unset_buffer(tdm_layer *layer)
-{
-       tdm_fbdev_layer_data *fbdev_layer = (tdm_fbdev_layer_data *) layer;
-
-       RETURN_VAL_IF_FAIL(fbdev_layer, TDM_ERROR_INVALID_PARAMETER);
-
-       fbdev_layer->display_buffer = NULL;
-       fbdev_layer->display_buffer_changed = 1;
-
-       return TDM_ERROR_NONE;
-}