Linux framebuffer驱动和自定义文件操作

Posted

技术标签:

【中文标题】Linux framebuffer驱动和自定义文件操作【英文标题】:Linux framebuffer driver and custom file operation 【发布时间】:2015-10-26 14:26:05 【问题描述】:

我实现了一个framebuffer 驱动程序,该驱动程序是从Linux 中的一个嵌入式系统项目中检索的,我需要做的非常简单:在触摸屏幕的地方画一个小矩形。

为了做到这一点,我想使用你可以在以下驱动程序代码中找到的函数xxxfb_fillrect()(省略了某些部分):

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/uaccess.h>
#include <linux/vmalloc.h>
#include <linux/console.h>

#define PCI_VENDOR_ID_XXX   0x10F610F6
#define PCI_DEVICE_ID_XXX   0x2864C826
#define PCI_CLASS_MASK      0x00FF

#define FB_NAME             "MFCC8556_vfb_"
#define FB_MAJOR            29
#define VIDEOMEMSIZE        (480*800*3)

#define FBIO_TEST           _IO('F', 0x21)

/* Global variable */

/*
 * Driver data
 */
//static char *videomemory;
static int fb_count = 3;
static u_long videomemorysize = VIDEOMEMSIZE;

/* array of framebuffer */
static struct fb_info **g_fb_list;

static struct fb_fix_screeninfo fix_default __initdata = 
    .id         =   FB_NAME,
    .smem_len   =   VIDEOMEMSIZE,
    .type       =   FB_TYPE_PACKED_PIXELS,
    .visual     =   FB_VISUAL_PSEUDOCOLOR,
    .xpanstep   =   0,
    .ypanstep   =   0,
    .ywrapstep  =   0, 
    .accel      =   FB_ACCEL_NONE,
;


static struct fb_var_screeninfo var_default __initdata = 
    .xres           = 800,
    .yres           = 480,
    .xres_virtual   = 800,
    .yres_virtual   = 480,
    .bits_per_pixel = 24,
    .red            = 0, 8, 0,
    .green          = 0, 8, 0,
    .blue           = 0, 8, 0,
    .grayscale      = 0,
    .activate       = FB_ACTIVATE_TEST,
    .height         = -1,
    .width          = -1,
    .pixclock       = 30060,
    .vmode          = FB_VMODE_NONINTERLACED,
;

static int xxxfb_init(void);
static int register_fb(struct fb_info *info);
static int set_screen_base(struct fb_info* info);
static int init_fb_info(struct fb_info *info, struct fb_ops *fbops, unsigned int id_no);
static int alloc_fb_info (struct fb_info **info);


/* ------------ Accelerated Functions --------------------- */

/*
 * We provide our own functions if we have hardware acceleration
 * or non packed pixel format layouts. If we have no hardware 
 * acceleration, we can use a generic unaccelerated function. If using
 * a pack pixel format just use the functions in cfb_*.c. Each file 
 * has one of the three different accel functions we support.
 */

/**
 *      xxxfb_fillrect - REQUIRED function. Can use generic routines if 
 *           non acclerated hardware and packed pixel based.
 *           Draws a rectangle on the screen.       
 *
 *      @info: frame buffer structure that represents a single frame buffer
 *  @region: The structure representing the rectangular region we 
 *       wish to draw to.
 *
 *  This drawing operation places/removes a retangle on the screen 
 *  depending on the rastering operation with the value of color which
 *  is in the current color depth format.
 */
void xxxfb_fillrect(struct fb_info *info, const struct fb_fillrect *region)

/*  Meaning of struct fb_fillrect
 *
 *  @dx: The x and y coordinates of the upper left hand corner of the 
 *  @dy: area we want to draw to. 
 *  @width: How wide the rectangle is we want to draw.
 *  @height: How tall the rectangle is we want to draw.
 *  @color: The color to fill in the rectangle with. 
 *  @rop: The raster operation. We can draw the rectangle with a COPY
 *        of XOR which provides erasing effect. 
 */

    struct fb_fillrect *tmp_fillrect;

    /*ptr=(unsigned long*)info->screen_base;
    //fill the screen base ///
    for(i=0; i<800*10; i++)
        *ptr=0x0000FF00;
        ptr++;
    */

    printk(KERN_DEBUG "\nfb_fillrect()");
    printk(KERN_DEBUG "\nFix Screen Info.id =%s\n", info->fix.id); 
/*  printk(KERN_INFO    "\nstruct fb_fillrect:\n"
                        "dx = %d\n"
                        "dy = %d\n"
                        "width = %d\n"
                        "height = %d\n"
                        "color = 0x%08X\n"
                        "rop = 0x%X\n___\n"
                        , region->dx, region->dy, region->width, region->height, region->color, region->rop); 
                        */
//  printk(KERN_INFO "_in fill_rectangle : screen_base = 0x%X\n0x_%02X_%02X_%02X_%02X\n...\n",(unsigned int)info->screen_base, *info->screen_base, *(info->screen_base+1), *(info->screen_base+2),*(info->screen_base+3));


    tmp_fillrect = kmalloc(sizeof(struct fb_fillrect), GFP_KERNEL);
    *tmp_fillrect = *region;

/*tmp_fillrect->dx=400;
    tmp_fillrect->dy=200;
    tmp_fillrect->width=100;
    tmp_fillrect->height=50;
    tmp_fillrect->color=0x0000FF00;
    tmp_fillrect->rop=0x0;

*/
//tmp = copy_from_user(tmp_fillrect, region, sizeof(struct fb_fillrect));

    printk(KERN_INFO    "\nstruct fb_fillrect:\n"
                        "dx = %d\n"
                        "dy = %d\n"
                        "width = %d\n"
                        "height = %d\n"
                        "color = 0x%08X\n"
                        "rop = 0x%X\n___\n"
                        , tmp_fillrect->dx, tmp_fillrect->dy, tmp_fillrect->width, tmp_fillrect->height, tmp_fillrect->color, tmp_fillrect->rop);

    //if (tmp) printk(KERN_ERR "**ERROR: copy_from_user = %d\n", tmp);

    cfb_fillrect(info, region);



...

int xxxfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)

    int ret = 0;

    printk(KERN_INFO "fb_ioctl()");
    mutex_lock(&info->lock);

    switch(cmd) 
    case FBIOGET_VSCREENINFO:
        printk(KERN_DEBUG "FBIOGET_VSCREENINFO");
        break;

    case FBIOGET_FSCREENINFO:
        printk(KERN_DEBUG "FBIOGET_FSCREENINFO");
        break;

    case FBIO_TEST:
        printk(KERN_DEBUG "FBIO_TEST");
        break;

    default: 
        printk(KERN_DEBUG "ioctl DEFAULT");
        break;
    

    mutex_unlock(&info->lock);

    return ret; 



    /*
     *  Frame buffer operations
     */

static struct fb_ops xxxfb_ops = 
    .owner          = THIS_MODULE,
    .fb_open        = xxxfb_open,
    .fb_read        = fb_sys_read,
    .fb_write       = fb_sys_write,
    .fb_release     = xxxfb_release,
    .fb_check_var   = xxxfb_check_var,
    .fb_set_par     = xxxfb_set_par,
    //.fb_setcolreg = xxxfb_setcolreg,
    .fb_blank       = xxxfb_blank,
    .fb_pan_display = xxxfb_pan_display,
    .fb_fillrect    = xxxfb_fillrect,   /* Needed !!! */
    .fb_copyarea    = xxxfb_copyarea,   /* Needed !!! */
    .fb_imageblit   = xxxfb_imageblit,  /* Needed !!! */
    .fb_cursor      = xxxfb_cursor,     /* Optional !!! */
    .fb_sync        = xxxfb_sync,
    .fb_ioctl       = xxxfb_ioctl,
    .fb_mmap        = xxxfb_mmap,
;

/* ------------------------------------------------------------------------- */

...

    /*
     *  Modularization
     */

module_init(xxxfb_init);
module_exit(xxxfb_exit);

MODULE_LICENSE("GPL");

但问题是,我不知道怎么称呼它。我最终在不使用fb_fillrect() 的情况下手动实现了矩形的绘制。

我知道这不是通常的open/rd/wr/... 操作,但它就在这里。我该如何使用它?我应该用ioctl() 调用它吗?如果是,为什么fb_fillrect 出现在帧缓冲区操作结构中?

提前感谢您的帮助。

【问题讨论】:

【参考方案1】:

fb_ops 中的函数是不直接暴露给用户空间的低级操作。相反,drivers/video/fbdev/core/fbmem.c 中有一个 fb_fops 结构,其中包含来自用户空间的 open/read/write/ioctl 的处理函数(参见下面的代码)。其中一些处理函数可能会随后调用驱动程序中的fb_ops 函数(请参阅do_fb_ioctl 函数)。

static const struct file_operations fb_fops = 
    .owner =    THIS_MODULE,
    .read =     fb_read,
    .write =    fb_write,
    .unlocked_ioctl = fb_ioctl,

    ...

;

static long fb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)

    struct fb_info *info = file_fb_info(file);

    if (!info)
        return -ENODEV;
    return do_fb_ioctl(info, cmd, arg);


static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
        unsigned long arg)

    struct fb_ops *fb;

    ...

    switch (cmd) 
    case FBIOGET_VSCREENINFO:
        ...
    case FBIOPUT_VSCREENINFO:
        ...
    case FBIOGET_FSCREENINFO:
        ...
    case FBIOPAN_DISPLAY:
        ...

    default:
        if (!lock_fb_info(info))
            return -ENODEV;
        fb = info->fbops;
        if (fb->fb_ioctl)
            ret = fb->fb_ioctl(info, cmd, arg);
        else
            ret = -ENOTTY;
        unlock_fb_info(info);
    
    return ret;

在其他情况下,fb_ops 函数可能由在 fbdev 之上工作的驱动程序(如 fbcon)使用。这是一个由帧缓冲区控制台驱动程序http://lxr.free-electrons.com/source/drivers/video/console/fbcon_cw.c#L80 直接调用的fb_fillrect 示例。

static void cw_clear(struct vc_data *vc, struct fb_info *info, int sy,
                  int sx, int height, int width)

      struct fbcon_ops *ops = info->fbcon_par;
      struct fb_fillrect region;

      ...

      info->fbops->fb_fillrect(info, &region);

【讨论】:

以上是关于Linux framebuffer驱动和自定义文件操作的主要内容,如果未能解决你的问题,请参考以下文章

linux驱动开发之framebuffer应用编程实践

Linux 帧缓冲子系统详解:LCD介绍framebuffer驱动框架LCD驱动源码分析

Linux驱动框架之framebuffer驱动框架

Linux驱动开发: FrameBuffe(LCD)驱动开发

linux驱动之framebuffer

linux驱动开发之framebuffer驱动介绍