Chinaunix首页 | 论坛 | 博客

分类: LINUX

2012-12-27 19:51:44

    作为一个数码相框项目,显示设备当然是必不可少的。本系统中,每一个显示设备管理器对应一个 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) |
给主人留下些什么吧!~~