您的位置:首页 > 编程语言 > C语言/C++

LCD驱动程序(1)初步编写LCD驱动程序

2017-03-08 16:57 351 查看
先参考内核里面自带的驱动程序,我们只是参考它的头文件而已

 /*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");
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息