作为一个数码相框项目,显示设备当然是必不可少的。本系统中,每一个显示设备管理器对应一个 struct disp_manager 结构体对象:
struct disp_manager {
char *name;
int xres;
int yres;
int bpp;
int line_width;
int pixel_width;
int screen_size;
unsigned char *mem;
int (*device_init)(void);
int (*put_pixel)(int x, int y, int color);
int (*clean_screen)(int color);
int (*advance_show_image)(int x, int y, struct image_info *image);
struct list_head list;
};
1.核心层 disp_core.c 简要分析:
static struct list_head manager_list;
/* 必须第一个被调用,用来初始化链表头 */
void disp_core_init(void)
{
INIT_LIST_HEAD(&manager_list);
}
void register_disp_manager(struct disp_manager *manager)
{
list_add(&manager->list, &manager_list);
}
void show_disp_manager(void)
{
struct disp_manager *manager;
struct list_head *pos;
list_for_each(pos, &manager_list)
{
manager = list_entry(pos, struct disp_manager, list);
printf("display manager:%s\n",manager->name);
}
}
struct disp_manager * get_disp_manager(char *name)
{
struct list_head *pos;
struct disp_manager *manager;
list_for_each(pos, &manager_list)
{
manager = list_entry(pos, struct disp_manager, list);
if(strcmp(manager->name, name) == 0)
return manager;
}
return NULL;
}
核心层主要提供一些接口供外部函数调用,在使用显示设备时,必须要先调用 disp_core_init() 函数,它是用来初始化一个链表头,所有系统注册过的显示设备管理器都会被加入该链表。同样,外部的函数想要使用解析器必须先调用 get_disp_manager() 来获得对应的显示设备管理器。show_disp_manager() 函数可以输出当前系统中所有注册过的显示设备管理器的名称。
2.LCD 管理器 fb.c 简要分析:
#define FB_DEVICE_NAME "/dev/fb0"
static struct disp_manager fb_manager = {
.name = "fb",
.device_init = fb_device_init,
.put_pixel = fb_put_pixel,
.clean_screen = fb_clean_screen,
.advance_show_image = fb_advance_show_image,
};
/* success return 0; error return -1 */
static int fb_device_init(void)
{
int fd_fb;
int screen_size;
struct fb_var_screeninfo var;
struct fb_fix_screeninfo fix;
fd_fb = open(FB_DEVICE_NAME, O_RDWR);
if (fd_fb < 0)
{
printf("can't open FB_DEVICE_NAME\n");
return -1;
}
ioctl(fd_fb, FBIOGET_VSCREENINFO, &var);
ioctl(fd_fb, FBIOGET_FSCREENINFO, &fix);
screen_size = var.xres * var.yres * var.bits_per_pixel / 8;
fb_manager.mem = (unsigned char *)mmap(NULL, screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);
if(fb_manager.mem < 0)
{
printf("fb mmap error\n");
return -1;
}
fb_manager.xres = var.xres;
fb_manager.yres = var.yres;
fb_manager.bpp = var.bits_per_pixel;
fb_manager.screen_size = screen_size;
fb_manager.line_width = var.xres * var.bits_per_pixel / 8;
fb_manager.pixel_width = var.bits_per_pixel / 8;
return 0;
}
/* success return 0; error return -1 */
static int fb_put_pixel(int x, int y, int color)
{
unsigned char *addr;
unsigned short *addr16;
unsigned int *addr32;
int red, green, blue;
if((x > fb_manager.xres) || (y > fb_manager.yres))
{
printf("put pixel out of lcd region\n");
return -1;
}
addr = fb_manager.mem + fb_manager.line_width * y + fb_manager.pixel_width * x;
addr16 = (unsigned short *)addr;
addr32 = (unsigned int *)addr;
switch(fb_manager.bpp)
{
case 8:
{
*addr = (unsigned char)color;
break;
}
case 16:
{
red = (color >> (16+3)) & 0x1f;
green = (color >> (8+2)) & 0x3f;
blue = (color >> 3) & 0x1f;
*addr16 = (red << 11) | (green << 5) | blue;
break;
}
case 32:
{
*addr32 = color;
break;
}
default:
{
printf("can't support %d bpp\n",fb_manager.bpp);
return -1;
}
}
return 0;
}
/* success return 0; error return -1 */
static int fb_clean_screen(int color)
{
unsigned char *addr;
unsigned short *addr16;
unsigned int *addr32;
int red, green, blue;
unsigned short color565;
int i = 0;
addr = fb_manager.mem;
addr16 = (unsigned short *)addr;
addr32 = (unsigned int *)addr;
switch(fb_manager.bpp)
{
case 8:
{
memset(addr, color, fb_manager.screen_size);
break;
}
case 16:
{
red = (color >> (16+3)) & 0x1f;
green = (color >> (8+2)) & 0x3f;
blue = (color >> 3) & 0x1f;
color565 = (red << 11) | (green << 5) | blue;
while(i < fb_manager.screen_size)
{
*addr16 = color565;
addr16 ++;
i += 2;
}
break;
}
case 32:
{
while(i < fb_manager.screen_size)
{
*addr32 = color;
addr32 ++;
i += 4;
}
break;
}
default:
{
printf("can't support %d bpp\n",fb_manager.bpp);
return -1;
}
}
return 0;
}
/* success return 0; error return -1 */
static int fb_advance_show_image(int x, int y, struct image_info *image)
{
int xlen, ylen; /* 显示的宽度和高度,单位为像素 */
int i;
unsigned char *src_data;
unsigned char *dst_data;
if((x > fb_manager.xres) || (y > fb_manager.yres))
{
printf("image out of lcd region\n");
return -1;
}
if(x+image->width > fb_manager.xres)
xlen = fb_manager.xres - x;
else
xlen = image->width;
if(y+image->height> fb_manager.yres)
ylen = fb_manager.yres - y;
else
ylen = image->height;
src_data = image->data;
dst_data = fb_manager.mem + fb_manager.line_width * y + fb_manager.pixel_width * x;
for(i=0; i {
memcpy(dst_data, src_data, xlen * image->bpp /8);
src_data += image->line_width;
dst_data += fb_manager.line_width;
}
return 0;
}
/* 向系统注册 LCD 管理器 */
void fb_manager_register(void)
{
register_disp_manager(&fb_manager);
}
fb_device_init() 函数很重要,它是根据底层驱动的信息来设置 LCD 的参数,例如:分辨率、bpp 等。任何 struct disp_manager 对象在使用前都必须调用成员函数 device_init() 来进行初始化。
3.简要测试函数编写:
int main(int argc, char *argv[])
{
struct disp_manager *fb_manager = NULL;
disp_core_init();
fb_manager_register();
fb_manager = get_disp_manager("fb");
if(fb_manager == NULL)
{
printf("can't get fb display manager\n");
return -1;
}
fb_manager->device_init();
fb_manager->clean_screen(0xff0000); //清屏,颜色为红色
……
}
——忠于梦想 勇于实践 linux_xpj@opencores.org
阅读(1957) | 评论(0) | 转发(0) |