ANDROID Porting系列七、Display Drivers

 

•功能

•实现您自己的驱动程序(驱动程序模板)

•故障排除

    本节介绍了如何显示驱动功能,并提供一个功能模板,旨在帮助您建立自己的特定于设备的驱动程序。

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_FSCREENINFOFBIOGET_VSCREENINFO输入/输出控制(IOCTL)调用以检索有关屏幕信息

•使用FBIOPUT_VSCREENINFOioctl,试图建立一个虚拟显示两倍的物理屏幕大小和设置像素格式rgb_565。如果成功,实现双缓冲的视频内存。

    当一个页面需要翻盖,Android就会再做FBIOPUT_VSCREENINFOioctl调用一个新的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上的双缓冲依靠顺利呈现页面翻转(详情请参阅功能)。

你可能感兴趣的:(ANDROID Porting系列七、Display Drivers)