•功能
•实现您自己的驱动程序(驱动程序模板)
•故障排除
本节介绍了如何显示驱动功能,并提供一个功能模板,旨在帮助您建立自己的特定于设备的驱动程序。
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上的双缓冲依靠顺利呈现页面翻转(详情请参阅功能)。