LINUX驱动之LCD驱动

1 前言LCD是Liquid Crystal Display的简称,也就是经常所说的液晶显示器,LCD能够支持彩色图像的显示和视频和播放,是一种非常重要的输出设备,对于LCD的驱动一般就是涉及framebuffer的编程,形象点说,framebuffer驱动负责把我们输入的内容转成送往LCD的信号,那LCD的驱动负责把信号转成LCD上显示的内容,两者是相互合作的关系.1.1FrameBuffe...
摘要由CSDN通过智能技术生成

1 前言

LCD是Liquid Crystal Display的简称,也就是经常所说的液晶显示器,LCD能够支持彩色图像的显示和视频和播放,是一种非常重要的输出设备,对于LCD的驱动一般就是涉及framebuffer的编程,形象点说,framebuffer驱动负责把我们输入的内容转成送往LCD的信号,那LCD的驱动负责把信号转成LCD上显示的内容,两者是相互合作的关系.

1.1FrameBuffer的概念

FrameBuffer又叫帧缓冲,是LINUX为操作显示设备提供的一个用户接口,用户应用程序可以通过FrameBuffer透明地访问不同类型的显示设备,从这方面来说,FrameBuffe是硬件设备显示缓冲区抽象,屏蔽图像硬件的底层差异,LINUX抽象出FrameBuffer这个帧缓冲区可以供用户应用直接读写,通过更改FrameBuffer中的内容,就可以立刻显示在LCD显示屏上,除此之外,FrameBuffer是一个标准的字符设备,
主设备号为29,对应于/dev/fb%d设备文件,FrameBuffer设备也是一种普通的内存设备,可以直接对其读写,比如执行"cp /dev/fb0 file.png"对屏幕进行抓屏

1.2FrameBuffer与应用程序的交互

在这里插入图片描述
在Linux中,FrameBuffer是一种能够提取图形的硬件设备,是用户进入图像界面的很好接口,它是显存抽象后的一种设备,它允许上层应用程序在直接进行读写操作,这种操作是抽象的,统一的,用户不比关心物理显存的位置,换页机制等具体细节,对于用户程序而言,它和/dev下面的其他设备没有什么区别,用户可以把FrameBuffer看成一块内存,我们想显示图片时只需要映射这块内存,向里面写入数据即可,后续的显示工作由LCD控制完成即可

1.3LCD显示原理

简单地讲,FrameBuffer驱动的功能就是分配一块内存作为显存,然后对LCD控制器的寄存器做一些设置,LCD显示器会不断从显存中获得数据,并将其显示在LCD显示器上,LCD显示器可以显示显存中的一个区域或者整个区域,具体点讲,通过FrameBuffer,应用程序用mmap()把分配在物理空间的显存映射到应用程序虚拟地址空间,应用程序只需要将显示的数据写入到这个内存空间,然后LCD控制器会自动将这个内存空间(显存)中的数据显示在LCD显示屏上,在linux内核中framebuffer驱动的核心在fbmem.c文件中实现,我们下面来分析这个过程

2 Fbmem.c分析:

#define FB_MAJOR		29

static int __init
fbmem_init(void)
{
   
	create_proc_read_entry("fb", 0, NULL, fbmem_read_proc, NULL);

	if (register_chrdev(FB_MAJOR,"fb",&fb_fops))
		printk("unable to get major %d for fb devs\n", FB_MAJOR);

	fb_class = class_create(THIS_MODULE, "graphics");
	if (IS_ERR(fb_class)) {
   
		printk(KERN_WARNING "Unable to create fb class; errno = %ld\n", PTR_ERR(fb_class));
		fb_class = NULL;
	}
	return 0;
}
#ifdef MODULE
module_init(fbmem_init);

可以看出在入口函数中注册了一个名为"fb"的字符设备和注册一个file_operations结构体"fb_fops"与之关联,注册的主设备号为29,还创建一个类,因为“fbmem.c”是通用的文件,故并不能直接使用这file_operations 结构的.read 等函数,这里的fbmem.c没有在设备类下创建设备,只有真正有硬件设备时才有必要在这个类下去创建设备,至于在哪里创建设备我们后面会提到,我们看到fb_fops的open函数

static int
fb_open(struct inode *inode, struct file *file)
{
   
	int fbidx = iminor(inode);
	struct fb_info *info;
	int res = 0;

	if (fbidx >= FB_MAX)
		return -ENODEV;
#ifdef CONFIG_KMOD
	if (!(info = registered_fb[fbidx]))
		try_to_load(fbidx);
#endif /* CONFIG_KMOD */
	if (!(info = registered_fb[fbidx]))
		return -ENODEV;
	if (!try_module_get(info->fbops->owner))
		return -ENODEV;
	file->private_data = info;
	if (info->fbops->fb_open) {
   
		res = info->fbops->fb_open(info,1);
		if (res)
			module_put(info->fbops->owner);
	}
	return res;
}

首先通过iminor(inode)得到这个设备节点的"次设备号"(这里假设为0),然后定义一个类型为struct fb_info*类型的结构体,从这个registered_fb[]数组里得到“以次设备号为0为下标”的一项赋值给这个info,若这个 info=registered_fd[0] 的 “fbops”有“fb_open”函数时就调用这个fb_open打开设备,至于registered_fb[]数组中的项是从哪里来的我们后面会说到,我们先来看看fb_fops的read函数

static ssize_t
fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
   
	unsigned long p = *ppos;
	struct inode *inode = file->f_path.dentry->d_inode;
	int fbidx = iminor(inode);
	struct fb_info *info = registered_fb[fbidx];
	u32 *buffer, *dst;
	u32 __iomem *src;
	int c, i, cnt = 0, err = 0;
	unsigned long total_size;

	if (!info || ! info->screen_base)
		return -ENODEV;

	if (info->state != FBINFO_STATE_RUNNING)
		return -EPERM;

	if (info->fbops->fb_read)
		return info->fbops->fb_read(info, buf, count, ppos);
	
	total_size = info->screen_size//设置屏幕大小

	if (total_size == 0)
		total_size = info->fix.smem_len;

	if (p >= total_size)
		return 0;

	if (count >= total_size)
		count = total_size;

	if (count + p > total_size)
		count = total_size - p;

	buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count,
			 GFP_KERNEL);//分配一个缓冲区
	if (!buffer)
		return -ENOMEM;

	src = (u32 __iomem *) (info->screen_base + p);//screen_base是指显存的基地址,这里是等于显存的基地址加上某个偏移量
	

	if (info->fbops->fb_sync)
		info->fbops->fb_sync(info);

	while (count) {
   
		c  = (count > PAGE_SIZE) ? PAGE_SIZE : count;
		dst = buffer;
		for (i = c >> 2; i--; )
			*dst++ = fb_readl(src++);//读源(从显存基地址+P 偏移)那里读到一个数据放到目标“*dst++”里.dst 是  buffer,buffer是 kmalloc()上面分配的空间.   
		if (c & 3
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值