您的位置:首页 > 移动开发 > Android开发

ANDROID Porting系列七、Display Drivers

2010-07-16 16:23 232 查看
 •功能
•实现您自己的驱动程序(驱动程序模板)
•故障排除

    本节介绍了如何显示驱动功能,并提供一个功能模板,旨在帮助您建立自己的特定于设备的驱动程序。
Android依靠在Linux / fb.h内核头文件的标准帧缓冲设备(/ dev/fb0或/ dev/graphics/fb0)和驱动程序。欲了解更多有关标准的Linux帧缓冲区信息,请参阅http://kernel.org的帧缓冲设备。

功能

在Android,每个窗口得到Surface对象实施,即SurfaceFlinger 将对象放置于framebuffer上(这就是system-wide screen composer)。每个Surface是双缓冲。后台缓冲区--drawing takes, 前台缓冲区--composition。
    当unlockCanvas()被调用时,后台缓冲区是已经画完,这意味着它将被呈现,且可以再次使用。 Android翻转前后缓冲区,缓冲区确保最少量的复制,而且总是有一个缓冲被SurfaceFlinger使用, (即确保屏幕没有闪烁或显示痕迹)。
     Android提出两项要求的驱动程序:一个可映射内存的线性地址空间,它可以直接写入和支持rgb_565像素格式。一个典型的帧显示包括:

•访问通过调用/ dev/fb0打开驱动
•使用FBIOGET_FSCREENINFO和FBIOGET_VSCREENINFO输入/输出控制(IOCTL)调用以检索有关屏幕信息
•使用FBIOPUT_VSCREENINFO的ioctl,试图建立一个虚拟显示两倍的物理屏幕大小和设置像素格式rgb_565。如果成功,实现双缓冲的视频内存。

    当一个页面需要翻盖,Android就会再做FBIOPUT_VSCREENINFO的ioctl调用一个新的y偏移指向其他视频内存缓冲区。这个ioctl反过来调用驱动程序的fb_pan_display(),以进行实际的翻转。如果没有足够的视频内存,内存使用和定期只是到视频内存复制时,到时候做翻转。分配显存和设置像素格式后,Android使用的mmap()映射到进程的地址空间的内存。所有写入到帧缓冲通过此mmaped内存中完成。
    为了保持足够的性能,帧缓冲内存应该缓存。如果您使用write-back,刷新前帧从DMA缓冲区写入到液晶缓存。如果这是不可能的,你可以使用write-through。作为最后的手段,你也可以使用未缓存的write-bugger内存,但性能会受到影响。
实现自己的驱动程序(驱动程序模板)

    下面的示例驱动程序提供了一个功能的例子,以帮助您建立自己的显示驱动程序。修改PGUIDE_FB
...宏根据需要以匹配您自己的设备硬件的要求。

/*

*  pguidefb.c

*

 *  Copyright 2007, Google Inc.

*

*  This program is free software; you can redistribute it and/or modify

*  it under the terms of the GNU General Public License version 2 as

*  published by the Free Software Foundation.

*/

 

 

/*

*ANDROID PORTING GUIDE: FRAME BUFFER DRIVER TEMPLATE

*

*This template is designed to provide the minimum frame buffer

*functionality necessary for Android to display properly on a new

*device.  The PGUIDE_FB macros are meant as pointers indicating

*where to implement the hardware specific code necessary for the new

*device.  The existence of the macros is not meant to trivialize the

*work required, just as an indication of where the work needs to be

*done.

*/

 

#include <linux/module.h>

#include <linux/kernel.h>

#include <linux/errno.h>

#include <linux/string.h>

#include <linux/slab.h>

#include <linux/delay.h>

#include <linux/mm.h>

#include <linux/fb.h>

#include <linux/init.h>

#include <linux/platform_device.h>

 

 

/* Android currently only uses rgb565 in the hardware framebuffer*/

#define ANDROID_BYTES_PER_PIXEL 2

 

/* Android will use double buffer in video if there is enough*/

#define ANDROID_NUMBER_OF_BUFFERS 2

 

/* Modify these macros to suit the hardware*/

 

#define PGUIDE_FB_ROTATE

     /* Do what is necessary to cause the rotation*/

 

#define PGUIDE_FB_PAN

     /* Do what is necessary to cause the panning*/

 

#define PGUIDE_FB_PROBE_FIRST

     /* Do any early hardware initialization*/

 

#define PGUIDE_FB_PROBE_SECOND

     /* Do any later hardware initialization*/

 

#define PGUIDE_FB_WIDTH 320

     /* Return the width of the screen*/

 

#define PGUIDE_FB_HEIGHT 240

     /* Return the heighth of the screen*/

 

#define PGUIDE_FB_SCREEN_BASE 0

     /* Return the virtual address of the start of fb memory*/

 

#define PGUIDE_FB_SMEM_START PGUIDE_FB_SCREEN_BASE

     /* Return the physical address of the start of fb memory*/

 

#define PGUIDE_FB_REMOVE

     /* Do any hardware shutdown*/

 

 

 

 

 

struct pguide_fb {

     int rotation;

     struct fb_info fb;

     u32               cmap[16];

};

 

static inline u32 convert_bitfield(int val, struct fb_bitfield*bf)

{

     unsigned int mask = (1 << bf->length) - 1;

 

     return (val >> (16 - bf->length) & mask) << bf->offset;

}

 

 

/* set the software color map.  Probably doesn't need modifying.*/

static int

pguide_fb_setcolreg(unsigned int regno, unsigned int red, unsigned int green,

            unsigned int blue, unsigned int transp, struct fb_info*info)

{

        struct pguide_fb *fb = container_of(info, struct pguide_fb, fb);

 

     if (regno < 16) {

           fb->cmap[regno] = convert_bitfield(transp, &fb->fb.var.transp) |

                         convert_bitfield(blue, &fb->fb.var.blue) |

                         convert_bitfield(green, &fb->fb.var.green) |

                         convert_bitfield(red, &fb->fb.var.red);

           return 0;

     }

     else {

           return 1;

     }

}

 

/* check var to see if supported by this device.  Probably doesn't

*need modifying.

*/

static int pguide_fb_check_var(struct fb_var_screeninfo*var, struct fb_info*info)

{

     if((var->rotate & 1) != (info->var.rotate & 1)) {

           if((var->xres != info->var.yres) ||

              (var->yres != info->var.xres) ||

              (var->xres_virtual != info->var.yres) ||

              (var->yres_virtual >

               info->var.xres*ANDROID_NUMBER_OF_BUFFERS) ||

              (var->yres_virtual < info->var.xres )) {

                 return -EINVAL;

           }

     }

     else {

           if((var->xres != info->var.xres) ||

              (var->yres != info->var.yres) ||

              (var->xres_virtual != info->var.xres) ||

              (var->yres_virtual >

               info->var.yres*ANDROID_NUMBER_OF_BUFFERS) ||

              (var->yres_virtual < info->var.yres )) {

                 return -EINVAL;

           }

     }

     if((var->xoffset != info->var.xoffset) ||

        (var->bits_per_pixel != info->var.bits_per_pixel) ||

        (var->grayscale != info->var.grayscale)) {

           return -EINVAL;

     }

     return 0;

}

 

 

/* Handles screen rotation if device supports it.*/

static int pguide_fb_set_par(struct fb_info*info)

{

     struct pguide_fb*fb = container_of(info, struct pguide_fb, fb);

     if(fb->rotation != fb->fb.var.rotate) {

           info->fix.line_length =

             info->var.xres*ANDROID_BYTES_PER_PIXEL;

           fb->rotation = fb->fb.var.rotate;

           PGUIDE_FB_ROTATE;

     }

     return 0;

}

 

 

/* Pan the display if device supports it.*/

static int pguide_fb_pan_display(struct fb_var_screeninfo*var, struct fb_info*info)

{

     struct pguide_fb*fb    __attribute__ ((unused)) 

         = container_of(info, struct pguide_fb, fb);

 

     /* Set the frame buffer base to something like:

        fb->fb.fix.smem_start + fb->fb.var.xres*

        ANDROID_BYTES_PER_PIXEL*var->yoffset

    */

     PGUIDE_FB_PAN;

 

     return 0;

}

 

 

static struct fb_ops pguide_fb_ops = {

     .owner          = THIS_MODULE,

     .fb_check_var   = pguide_fb_check_var,

     .fb_set_par     = pguide_fb_set_par,

     .fb_setcolreg   = pguide_fb_setcolreg,

     .fb_pan_display = pguide_fb_pan_display,

 

     /* These are generic software based fb functions*/

     .fb_fillrect    = cfb_fillrect,

     .fb_copyarea    = cfb_copyarea,

     .fb_imageblit   = cfb_imageblit,

};

 

 

static int pguide_fb_probe(struct platform_device*pdev)

{

     int ret;

     struct pguide_fb*fb;

     size_t framesize;

     uint32_t width, height;

 

     fb = kzalloc(sizeof(*fb), GFP_KERNEL);

     if(fb == NULL) {

           ret = -ENOMEM;

           goto err_fb_alloc_failed;

     }

     platform_set_drvdata(pdev, fb);

 

     PGUIDE_FB_PROBE_FIRST;

     width = PGUIDE_FB_WIDTH;

     height = PGUIDE_FB_HEIGHT;

 

 

     fb->fb.fbops      = &pguide_fb_ops;

 

     /* These modes are the ones currently required by Android*/

 

     fb->fb.flags      = FBINFO_FLAG_DEFAULT;

     fb->fb.pseudo_palette   = fb->cmap;

     fb->fb.fix.type         = FB_TYPE_PACKED_PIXELS;

     fb->fb.fix.visual = FB_VISUAL_TRUECOLOR;

     fb->fb.fix.line_length = width*ANDROID_BYTES_PER_PIXEL;

     fb->fb.fix.accel  = FB_ACCEL_NONE;

     fb->fb.fix.ypanstep = 1;

 

     fb->fb.var.xres         = width;

     fb->fb.var.yres         = height;

     fb->fb.var.xres_virtual = width;

     fb->fb.var.yres_virtual = height*ANDROID_NUMBER_OF_BUFFERS;

     fb->fb.var.bits_per_pixel = 16;

     fb->fb.var.activate     = FB_ACTIVATE_NOW;

     fb->fb.var.height = height;

     fb->fb.var.width  = width;

 

     fb->fb.var.red.offset = 11;

     fb->fb.var.red.length = 5;

     fb->fb.var.green.offset = 5;

     fb->fb.var.green.length = 6;

     fb->fb.var.blue.offset = 0;

     fb->fb.var.blue.length = 5;

 

     framesize = width*height*

       ANDROID_BYTES_PER_PIXEL*ANDROID_NUMBER_OF_BUFFERS;

     fb->fb.screen_base = PGUIDE_FB_SCREEN_BASE;

     fb->fb.fix.smem_start = PGUIDE_FB_SMEM_START;

     fb->fb.fix.smem_len = framesize;

 

     ret = fb_set_var(&fb->fb, &fb->fb.var);

     if(ret)

           goto err_fb_set_var_failed;

 

     PGUIDE_FB_PROBE_SECOND;

 

     ret = register_framebuffer(&fb->fb);

     if(ret)

           goto err_register_framebuffer_failed;

 

     return 0;

 

 

err_register_framebuffer_failed:

err_fb_set_var_failed:

     kfree(fb);

err_fb_alloc_failed:

     return ret;

}

 

static int pguide_fb_remove(struct platform_device*pdev)

{

     struct pguide_fb*fb = platform_get_drvdata(pdev);

 

     PGUIDE_FB_REMOVE;

 

     kfree(fb);

     return 0;

}

 

 

static struct platform_driver pguide_fb_driver = {

     .probe            = pguide_fb_probe,

     .remove           = pguide_fb_remove,

     .driver = {

           .name = "pguide_fb"

     }

};

 

static int __init pguide_fb_init(void)

{

     return platform_driver_register(&pguide_fb_driver);

}

 

static void __exit pguide_fb_exit(void)

{

     platform_driver_unregister(&pguide_fb_driver);

}

 

module_init(pguide_fb_init);

module_exit(pguide_fb_exit);

 

MODULE_LICENSE("GPL");


疑难解答

下面的问题都具有类似的原因:

•数字键:在拨号的应用程序,当按下数字键拨打一个电话号码,该号码不显示在屏幕上,直到下一个数字后,已被按下。

•箭头键:当按下箭头键,所需的图标没有得到强调。例如,如果您通过在应用程序菜单图标浏览,您可能会注意到,当您使用箭头键来浏览选项之间时,图标预期不按您预期突出显示。

    这两个问题是由于不正确的执行情况的帧缓冲区的页面翻动。关键事件被捕获,但图形界面呈现每一帧滞后。

Android上的双缓冲依靠顺利呈现页面翻转(详情请参阅功能)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: