WDS2期第15课 1 内核LCD驱动层次分析 fbmem.c -- register_framebuffer -- 硬件 抽象出来的fbmem.c依赖底层硬件相关的数组registered_fb


在这里插入图片描述

分析内核自带LCD驱动程序drivers\video\fbmem.c

内核自带的LCD驱动程序,在drivers\video\fbmem.c中,fbmem.c提供的都是抽象的,具体的实现依赖里边的数组registered_fb[iminor(inode)],fb帧缓冲区(Frame Buffer),可以看到以下步骤:
在这里插入图片描述

major
fops
register_chrdev
class_create
没有 class_device_create
...
static const struct file_operations fb_fops = {
	.owner =	THIS_MODULE,
	.read =		fb_read,
	.write =	fb_write,
...
static int __init
fbmem_init(void)
{
	create_proc_read_entry("fb", 0, NULL, fbmem_read_proc, NULL);
	// major register_chrdev fops
	if (register_chrdev(FB_MAJOR,"fb",&fb_fops)) 
		printk("unable to get major %d for fb devs\n", FB_MAJOR);
	// class_create
	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;
}

查看open函数,和read函数,

static int
fb_open(struct inode *inode, struct file *file)
{
	int fbidx = iminor(inode); // 获取次设备号
	
	if (!(info = registered_fb[fbidx])) // 以此设备号为数组下标赋值给fb_info

		res = info->fbops->fb_open(info,1); // 调用open
	return res;
}

static ssize_t
fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
	int fbidx = iminor(inode);	// 获取次设备号
	struct fb_info *info = registered_fb[fbidx]; // 以次设备号为数组下标赋值给struct fb_info
	
	if (info->fbops->fb_read) // 有read就read
		return info->fbops->fb_read(info, buf, count, ppos);	

	src = (u32 __iomem *) (info->screen_base + p); // 无read读取显存的缓存
	
	*dst++ = fb_readl(src++);
	
	if (copy_to_user(buf, buffer, c)) {	 // 将读取的内容拷贝到用户空间

为fbmem.c提供硬件设备的数组registered_fb,register_framebuffer为fbmem.c和硬之间桥梁

fbmem.c提供的都是抽象的,具体的实现依赖里边的数组registered_fb[iminor(inode)],也在里边定义,修改也是,

struct fb_info *registered_fb[FB_MAX] __read_mostly; // 定义

// fbmem.c依赖register_framebuffer,register_framebuffer会把底层设备向上注册
int
register_framebuffer(struct fb_info *fb_info)
{
	// device_create对应于前面fb_class = class_create(THIS_MODULE, "graphics");
	// 		创建设备节点
	fb_info->dev = device_create(fb_class, fb_info->device,
				     MKDEV(FB_MAJOR, i), "fb%d", i);
				     
	fb_add_videomode(&mode, &fb_info->modelist);
	registered_fb[i] = fb_info;						// 修改

	event.info = fb_info;

硬件相关以drivers\video\s3c2410fb.c为例

有很多驱动程序都会调用register_framebuffer函数,如我们的drivers\video\s3c2410fb.c,进去简单看看,
在这里插入图片描述

// 入口函数  
int __devinit s3c2410fb_init(void)
{
	return platform_driver_register(&s3c2410fb_driver); // platform_driver_register --> add
}

static struct platform_driver s3c2410fb_driver = {
	.probe		= s3c2410fb_probe,
	.remove		= s3c2410fb_remove,
	.suspend	= s3c2410fb_suspend,
	.resume		= s3c2410fb_resume,
	.driver		= {
		.name	= "s3c2410-lcd", // 会根据name寻找同名dev
		.owner	= THIS_MODULE,
	},
};

// 首先根据platform_device获取硬件信息,然后分配struct fb_info,设置,注册framebuffer
static int __init s3c2410fb_probe(struct platform_device *pdev)
{
	// 获取硬件信息,
	mach_info = pdev->dev.platform_data;
	
	// 然后分配struct fb_info
	fbinfo = framebuffer_alloc(sizeof(struct s3c2410fb_info), &pdev->dev);
	
	// 设置
	fbinfo->fix.type	    = FB_TYPE_PACKED_PIXELS;
	fbinfo->fix.type_aux	    = 0;	
	
	// 注册framebuffer
	ret = register_framebuffer(fbinfo);

fbmem.c找到硬件信息的例子,如获取分辨率

如果在用户空间想获得屏幕的分辨率,通过fops中的fb_ioctl可以获得可变的屏幕信息FBIOGET_VSCREENINFO V(var)

drivers\video\fbmem.c
static int 
fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
	 unsigned long arg)
{
	int fbidx = iminor(inode); // 获取次设备号
	struct fb_info *info = registered_fb[fbidx]; // 以次设备号为下标获取struct  fb_info  registered_fb数组很重要
	struct fb_ops *fb = info->fbops; 
	case FBIOGET_VSCREENINFO:
		return copy_to_user(argp, &info->var,	// 通过struct fb_info找到var把结果拷贝到用户空间
				    sizeof(var)) ? -EFAULT : 0;

include\linux\fb.h
struct fb_info {
	int node;
	int flags;
	struct fb_var_screeninfo var;	/* Current var */ // struct fb_info包含var结构
	struct fb_fix_screeninfo fix;	/* Current fix */

include\linux\fb.h
struct fb_var_screeninfo {
	__u32 xres;			/* visible resolution		*/ // x y 方向的分辨率
	__u32 yres;
	__u32 xres_virtual;		/* virtual resolution		*/
	__u32 yres_virtual;				  

*** 小结fbmem.c <---- register_framebuffer ----> 硬件

fbmem.c提供抽象的代码,主要依赖数组registered_fb[iminor(inode)]的项获取硬件相关代码,而这个数组由register_framebuffer函数设置,register_framebuffer函数还完成自动创建设备节点的任务device_create,完成向上注册设备,而硬件部分就跟fbmem.c分离,由各自的芯片什么去完成如drivers\video\s3c2410fb.c然后调用register_framebuffer完成向上注册设备,
在这里插入图片描述

最终总结写LCD驱动应该以下步骤:

1. 分配struct fb_infoframebuffer_alloc(sizeof(struct xxxfb_info), &pdev->dev);

2. 设置

3. 注册register_framebuffer

4. 硬件相关操作

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值