add initialization of framebuffer device 60/61360/1
authorRoman Peresipkyn <r.peresipkyn@samsung.com>
Fri, 29 Jan 2016 14:51:19 +0000 (16:51 +0200)
committerSooChan Lim <sc1.lim@samsung.com>
Mon, 7 Mar 2016 10:51:49 +0000 (19:51 +0900)
Change-Id: I0b0fb08b4627d2ef5cd3a5a7f4b8653be3d7b499
Signed-off-by: Roman Peresipkyn <r.peresipkyn@samsung.com>
src/tdm_fbdev.c
src/tdm_fbdev.h

index 54314d49d74830ab79cf2cfab4f220de35346b95..2cdc1e0786f49f39a9ea58f2069b18044eb131db 100644 (file)
 
 #include <tdm_helper.h>
 
-/*
- * TODO: How should it be named?
- */
-#define TDM_FBDEV_NAME "vigs"
+#define TDM_FBDEV_NAME "fbdev"
 
 static tdm_func_display fbdev_func_display =
 {
@@ -48,24 +45,274 @@ static tdm_func_display fbdev_func_display =
     NULL,    //layer_create_capture
 };
 
+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;
+    struct fb_var_screeninfo vinfo;
+    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;
+
+    /*
+     * Almost all framebuffers support off screen rendering.
+     * The code bellow requests Framebuffer to allocate memory equals to three
+     * buffers each of which width*height size. While the first drawn
+     * framebuffer's area is displaying the second or the third is redrawing
+     * or compositing by some application. When timer was expired or vblank
+     * was received Framebufer's areas swap, thus the second or the third is
+     * displaying and first is redrawing or compositing. Simple representation
+     * of what was said bellow
+     *
+     *                    SWAP Event                SWAP Event
+     *                        |                         |
+     *    +-------------+     |     +-------------+     |      +-------------+
+     *    |             |     |     |             |     |      |  Redrawing  |
+     *    | Displaying  |     |     |   queued    |     |      |     or      |
+     *    |             |     |     |             |     |      | Compositing |
+     *    +-------------+     |     +-------------+     |      +-------------+
+     *    |  Redrawing  |     |     |             |     |      |             |
+     *    |     or      | +-------> | Displaying  | +--------> |   queued    |
+     *    | Compositing |     |     |             |     |      |             |
+     *    +-------------+     |     +-------------+     |      +-------------+
+     *    |             |     |     |  Redrawing  |     |      |             |
+     *    |   queued    |     |     |     or      |     |      | Displaying  |
+     *    |             |     |     | Compositing |     |      |             |
+     *    +-------------+     |     +-------------+     |      +-------------+
+     *                        |                         |
+     */
+    vinfo.yres_virtual = vinfo.yres * MAX_BUF;
+
+    ret = ioctl(fbdev_data->fbdev_fd, FBIOPAN_DISPLAY, vinfo);
+    if(ret < 0)
+    {
+        TDM_INFO("page flip not supported,  errno=%d", errno);
+        vinfo.yres_virtual = vinfo.yres;
+
+        /*
+         * TODO: Does FBIOPAN_DISPLAY ioctl must be invoked for the second time?
+         */
+        ret = ioctl(fbdev_data->fbdev_fd, FBIOPAN_DISPLAY, vinfo);
+        if(ret < 0)
+        {
+            TDM_ERR("FBIOPAN_DISPLAY ioctl failed, errno=%d", errno);
+            goto close_1;
+        }
+    }
+
+    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;
+    }
+
+    /*
+     * TODO: Size of framebuffer must be aligned to system page size before
+     *  it is mapped
+     */
+    fbdev_data->size = finfo.line_length * vinfo.yres * MAX_BUF;
+
+    fbdev_data->vaddr = mmap(0, fbdev_data->size, PROT_READ|PROT_WRITE,
+            MAP_SHARED, fbdev_data->fbdev_fd, 0);
+    if (fbdev_data->vaddr == MAP_FAILED)
+    {
+        TDM_ERR("MMap framebuffer failed, errno=%d", errno);
+        goto close_1;
+    }
+
+    memset(fbdev_data->vaddr, 0, fbdev_data->size);
+
+    /*
+     * 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);
+
+    free(fbdev_data);
+    fbdev_data = NULL;
 }
 
 tdm_backend_data*
 tdm_fbdev_init(tdm_display *dpy, tdm_error *error)
 {
-       (void) fbdev_func_display;
+    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(fbdev_data));
+    if (!fbdev_data)
+    {
+        TDM_ERR("alloc failed");
+        if(error)
+            *error = TDM_ERROR_OUT_OF_MEMORY;
+        return NULL;
+    }
+
+    ret = tdm_backend_register_func_display(dpy, &fbdev_func_display);
+    if (ret != TDM_ERROR_NONE)
+        goto failed;
+
+    fbdev_data->dpy = dpy;
+
+    /*
+     * TODO: does somebody open framebuffer device beside us?
+     */
+    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;
+    }
+
+
+    TDM_INFO("init success!");
+
+    if(error)
+        *error = TDM_ERROR_NONE;
+
+    return (tdm_backend_data*)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 =
 {
-    "vigs",
+    "fbdev",
     "Samsung",
     TDM_BACKEND_ABI_VERSION,
     tdm_fbdev_init,
index a2c05fd8638112095996e00b454d5a8e6384e58b..c57a513f2a75cab6d82e529766ed732ce662f834 100644 (file)
 #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 3
+
 /* drm backend functions (display) */
 tdm_error    fbdev_display_get_capabilitiy(tdm_backend_data *bdata, tdm_caps_display *caps);
 tdm_output** fbdev_display_get_outputs(tdm_backend_data *bdata, int *count, tdm_error *error);
@@ -45,4 +50,18 @@ 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);
 
+typedef struct _tdm_fbdev_data
+{
+    int fbdev_fd;
+
+    tdm_display *dpy;
+
+    struct fb_fix_screeninfo finfo;
+    struct fb_var_screeninfo vinfo;
+
+    void *vaddr;
+    size_t size;
+}tdm_fbdev_data;
+
+
 #endif /* _TDM_fbdev_H_ */