[英]Linux framebuffer driver and custom file operation
I implemented a framebuffer
driver retrieved from a former project in Linux for an embedded system and what I need to do is quite simple: draw a small rectangle where the screen is touched. 我实现了一个从Linux以前的项目中获取的用于嵌入式系统的framebuffer
驱动程序,而我需要做的很简单:在触摸屏幕的地方绘制一个小矩形。
In order to do this, I want to use the function xxxfb_fillrect()
that you can find in the following driver code (some parts are omitted) : 为此,我想使用在以下驱动程序代码中可以找到的功能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");
But the thing is, I have no idea how to call it. 但问题是,我不知道如何称呼它。 I ended up implementing the drawing of the rectangle manually without using this fb_fillrect()
. 我最终不使用此fb_fillrect()
来手动实现矩形的绘制。
I know this is not a usual open/rd/wr/
... operation, but it is here. 我知道这不是通常的open/rd/wr/
...操作,但它在这里。 How do I use it ? 如何使用? Should I call it with ioctl()
? 我应该用ioctl()
调用它吗? If yes, why is fb_fillrect
appearing in the frame buffer operations struct ? 如果是,为什么fb_fillrect
出现在帧缓冲区操作struct中?
Thank you in advance for your help. 预先感谢您的帮助。
The functions in fb_ops
are low level operations not directly exposed to user-space. fb_ops
中的函数是低级操作,不会直接暴露给用户空间。 Instead, there is a fb_fops
struct in drivers/video/fbdev/core/fbmem.c
that contains the handler functions for the open/read/write/ioctl
from user-space (see code below). 相反,在drivers/video/fbdev/core/fbmem.c
中有一个fb_fops
结构,其中包含用户空间中open/read/write/ioctl
的处理函数(请参见下面的代码)。 Some of those handler functions may call subsequently call the fb_ops
functions from your driver (see do_fb_ioctl
function). 其中一些处理程序函数可能会随后调用驱动程序中的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;
}
In other cases, fb_ops
functions may be used by drivers like fbcon
that work on top of fbdev
. 在其他情况下, fb_ops
可被fbcon
类的驱动程序使用,这些驱动程序可在fbdev
之上运行。 Here is an example of fb_fillrect
being called directly by a framebuffer console driver http://lxr.free-electrons.com/source/drivers/video/console/fbcon_cw.c#L80 . 这是帧缓冲控制台驱动程序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, ®ion);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.