先参考内核里面自带的驱动程序,我们只是参考它的头文件而已
/*1.分配一个fb_info结构体*/
30 s5p_lcd=framebuffer_alloc(sizeof(struct s5p_lcd), &pdev->dev);
31 //这里为什么需要一个大小,内核里面有个经常有个取巧的办法,分配一个结构体
,本来这个结构体只有这么大,它会额外分配一部分空间给你,然后你原本那个大小的
里面有个私有指针,指向它。你可以往里面存一些你觉得有意义的数据
不信的话我们可以看一下framebuffer_alloc的源代码
struct fb_info *framebuffer_alloc(size_t size, struct device *dev)
{
#define BYTES_PER_LONG (BITS_PER_LONG/8)
#define PADDING (BYTES_PER_LONG - (sizeof(struct fb_info) % BYTES_PER_LONG))
int fb_info_size = sizeof(struct fb_info);
struct fb_info *info;
char *p;
if (size)
fb_info_size += PADDING;
p = kzalloc(fb_info_size + size, GFP_KERNEL);//看这里 fb_info_size还要加一个size。
if (!p)
return NULL;
info = (struct fb_info *) p;
if (size)
info->par = p + fb_info_size; //par指向额外分配的一段空间
info->device = dev;
#ifdef CONFIG_FB_BACKLIGHT
mutex_init(&info->bl_curve_mutex);
#endif
return info;
#undef PADDING
#undef BYTES_PER_LONG
}
在我们驱动程序中要设置fb_info这个结构体,我们来看看这个结构体中有什么东西
我们前面说了固定参数
struct fb_fix_screeninfo fix;/* Current fix */ //这里的意思是固定的参数
我们来看看这个结构体里面有什么东西
__u32 visual; /* see FB_VISUAL_* */ //我们来看看这个宏
我们在来看可变信息
看看可变信息里面有什么
struct fb_bitfield blue; //看看这个结构体struct fb_bitfield
struct fb_bitfield transp;/* transparency*///透明色,我们没有透明度 struct fb_bitfield {
__u32 offset; /* beginning of bitfield */
__u32 length; /* length of bitfield */
__u32 msb_right;/* != 0 : Most significant bit is */
/* right */
}; 第一个是从哪一位开始,第二个是长度,第三个是 最重要的一位,如果最重要的一位在最右边 那么这里应该设置为不等于0;
下面我们来设置我们的fops
我们看其他的驱动程序,会发现一个共同点
static struct fb_ops tiny_lcdfb_ops = {
.owner = THIS_MODULE,
.fb_fillrect = cfb_fillrect, //这一个是什么意思呢,从英文名字可以看出是填充矩形的意思。
.fb_copyarea = cfb_copyarea, //拷贝一个区域
.fb_imageblit = cfb_imageblit,
}; 这几个fops基本上在每个lcd驱动上都会出现,共用的
所以我们也来参照一下
很明显是对显存的一些操作。
经过上面这些操作,我们驱动程序变成这样的
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/err.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/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/cpufreq.h>
#include <asm/io.h>
#include <asm/div64.h>
#include <asm/mach/map.h>
#include <mach/regs-lcd.h>
#include <mach/regs-gpio.h>
#include <mach/fb.h>
static struct fb_info *s5p_info;
static struct fb_ops s5p_lcdfb_ops = {
.owner = THIS_MODULE,
//.fb_setcolreg= tiny_lcdfb_setcolreg,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
};
static int lcd_init(void)
{
int res;
/*1.分配一个fb_info结构体*/
s5p_info=framebuffer_alloc(0,NULL);
if (!s5p_info)
{
printk("framebuffer_alloc error");
return -ENOMEM;
}
//这里为什么需要一个大小,内核里面有个经常有个取巧的办法,分配一个结构体,本来这个结构体只有这么大,它会额外分配一部分空间给你,然后你原本那个大小的里面有个私有指针,指向它。你可以往里面存一些你觉得有意义的数据。
//但是这里我们不需要额外的那段空间,所以这里写为0,后面写为NULL
/*2.设置*/
/*2.1设置固定的参数*/
/*2.1.1名字*/
strcpy(s5p_info->fix.id,"ghlcd");
/*2.1.2 设置显存的长度*/
/*这里需要我们去看LCD的手册*/
s5p_info->fix.len=800*480*4;
/*2.1.3 type*/
s5p_info->fix.type=FB_TYPE_PACKED_PIXELS;
/*2.1.4 visual*/
s5p_info->fix.visual=VISUAL_TRUECOLOR;
/*2.1.5 一行的长度单位是字节*/
s5p_info->fix.line_length=800*4;
/*2.2设置可变的参数*/
/*2.2.1 x方向的分辨率*/
s5p_info->var.xres=800;
/*2.2.2 y方向的分辨率*/
s5p_info->var.yres=480;
/*2.2.3 x方向的虚拟分辨率*/
s5p_info->var.xres_virtual=800;
/*2.2.4 y方向的虚拟分辨率*/
s5p_info->var.yres_virtual=480;
/*2.2.5 每个像素用多少位*/
s5p_info->var.bits_per_pixel=32;
/*2.2.6 红色从那一位开始*/
//RGB 8:8:8
s5p_info->var.red.offset = 16;
/*2.2.7 长度*/
s5p_info->var.red.length =8;
s5p_info>var.green.offset= 8;
s5p_info->var.green.length = 8;
s5p_info->var.blue.offset = 0;
s5p_info->var.blue.length = 8;
/*2.2.8 activate */
s5p_info->var.activate = FB_ACTIVATE_NOW;
/*2.3设置fops操作函数*/
s5p_info->fbfops=&s5p_lcdfb_ops;
/*2.4其他的设置*/
//tiny_lcd->screen_base = ; /*显存的虚拟起始地址*/
s5p_info->screen_size = 800*480*4;
s5p_info->pseudo_palette = pseudo_pal; //这个是假的调色板
/*3.硬件相关的操作*/
/*3.1配置相应的GPIO为LCD管脚*/
/*3.2根据LCD手册设置LCD控制器,让它可以发出正确的信号*/
/*3.3分配framebuffer,并把物理地址告诉LCD控制器*/
//s5p_info->var.smem_start=xxxxx;
/*4.注册*/
res = register_framebuffer(s5p_info);
if (ret < 0) {
printk(KERN_ERR "Failed to register framebuffer device: %d\n",ret);
return ENOMEM;
}
return 0;
}
static void lcd_exit(void)
{
}
module_init(lcd_init);
module_exit(lcd_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("EIGHT");