ANDROID Porting系列七、Display Drivers

本文介绍如何为Android设备创建自定义的帧缓冲驱动程序。详细解释了Android如何利用帧缓冲进行显示,并提供了一个驱动模板帮助开发者快速上手。此外,还讨论了一些常见的驱动问题及其解决方法。
AI助手已提取文章相关产品:

•功能

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

•故障排除

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

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上的双缓冲依靠顺利呈现页面翻转(详情请参阅功能)。

您可能感兴趣的与本文相关内容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值