framebuffer驱动详解3——fb驱动分析具体操作层

以下内容源于朱有鹏嵌入式课程的学习与整理,如有侵权请告知删除。

前言

博文fb驱动框架分析(核心层)已经对内核驱动维护者编写的fb驱动框架进行讲解。

接下来将对具体的fb驱动文件进行分析。这些驱动文件是驱动工程师要完成的部分。

root@ubuntu:省略部分路径/x210_kernel/drivers/video# cd samsung/
root@ubuntu:省略部分路径/x210_kernel/drivers/video/samsung# ls *.o
built-in.o  s3cfb_fimd6x.o  s3cfb.o
root@ubuntu:省略部分路径/x210_kernel/drivers/video/samsung# 

通过检查内核编译结果相应目录中的.o文件,得知具体操作层主要涉及的文件:

(1)drivers/video/samsung/s3cfb.c,这是驱动主要文件。

(2)drivers/video/samsung/s3cfb_fimd6x.c,里面有很多LCD硬件操作的函数。

(3)arch/arm/mach-s5pv210/mach-x210.c,负责提供platform_device。

(4)arch/arm/plat-s5p/devs.c,为platform_device提供一些硬件描述信息。

这里主要分析drivers/video/samsung/s3cfb.c文件。

1、实现方式为平台总线

这是因为使用到SoC内部的LCD控制器,它属于内部外设,故而可以借用平台总线实现一些机制。

static int __init s3cfb_register(void)
{
	platform_driver_register(&s3cfb_driver);

	return 0;
}
static void __exit s3cfb_unregister(void)
{
	platform_driver_unregister(&s3cfb_driver);
}

module_init(s3cfb_register);
module_exit(s3cfb_unregister);

 

2、平台驱动结构体变量:s3cfb_driver

static struct platform_driver s3cfb_driver = {
	.probe = s3cfb_probe,
	.remove = __devexit_p(s3cfb_remove),
	.driver = {
		   .name = S3CFB_NAME,  //#define S3CFB_NAME	"s3cfb"
		   .owner = THIS_MODULE,
	},
};

由于平台总线下,驱动与设备是根据name来进行匹配的,这里驱动的名字是“s3cfb”,因此和驱动匹配的设备的名字应该也叫“s3cfb”。

 

3、s3c_device_fb设备

(1)我们找一下名字叫“s3cfb”的平台设备。在linux系统x210_kernel目录下,使用“ grep -nr “s3cfb” ./ ”命令查找贴切的设备定义,得知其位于arch/arm/plat-s5p/devs.c文件中,内容如下所示。由此可知,s3c_device_fb这个平台设备的名字叫做“s3cfb”。

struct platform_device s3c_device_fb = {
	.name		  = "s3cfb",                 //定义在这里
	.id		  = -1,   //id表示次设备号,-1表示自动分配次设备号
	.num_resources	  = ARRAY_SIZE(s3cfb_resource),
	.resource	  = s3cfb_resource,
	.dev		  = {
		.dma_mask		= &fb_dma_mask,
		.coherent_dma_mask	= 0xffffffffUL
	}
};

(2)在板级文件mach-x210.c中,s3c_device_fb这个平台设备与其他平台设备一样,被写入平台设备数组smdkc110_devices[ ]中,然后再利用smdkc110_machine_init()函数对这些平台设备进行注册,过程如下所示。

static struct platform_device *smdkc110_devices[] __initdata = {
#ifdef CONFIG_FIQ_DEBUGGER
	&s5pv210_device_fiqdbg_uart2,
#endif
//省略部分代码

#ifdef CONFIG_FB_S3C
	&s3c_device_fb,   //这里
#endif
//省略部分代码

}
static void __init smdkc110_machine_init(void)
{
	//省略部分代码
	platform_add_devices(smdkc110_devices, ARRAY_SIZE(smdkc110_devices));
    //省略部分代码
}

(3)我们再看一下s3cfb_resource,其内容如下。

static struct resource s3cfb_resource[] = {
	[0] = {
		.start = S5P_PA_LCD,
		.end   = S5P_PA_LCD + S5P_SZ_LCD - 1,
		.flags = IORESOURCE_MEM,
	},
	[1] = {
		.start = IRQ_LCD1,
		.end   = IRQ_LCD1,
		.flags = IORESOURCE_IRQ,
	},
	[2] = {
		.start = IRQ_LCD0,
		.end   = IRQ_LCD0,
		.flags = IORESOURCE_IRQ,
	},
};

 

4、s3cfb_probe()函数分析

s3cfb_probe()函数内容如下:

static int __devinit s3cfb_probe(struct platform_device *pdev)
{
	struct s3c_platform_fb *pdata;
	struct s3cfb_global *fbdev;
	struct resource *res;
	int i, j, ret = 0;

	fbdev = kzalloc(sizeof(struct s3cfb_global), GFP_KERNEL);
	if (!fbdev) {
		dev_err(&pdev->dev, "failed to allocate for "
			"global fb structure\n");
		ret = -ENOMEM;
		goto err_global;
	}
	fbdev->dev = &pdev->dev;

	fbdev->regulator = regulator_get(&pdev->dev, "pd");
	if (!fbdev->regulator) {
		dev_err(fbdev->dev, "failed to get regulator\n");
		ret = -EINVAL;
		goto err_regulator;
	}
	ret = regulator_enable(fbdev->regulator);
	if (ret < 0) {
		dev_err(fbdev->dev, "failed to enable regulator\n");
		ret = -EINVAL;
		goto err_regulator;
	}
	pdata = to_fb_plat(&pdev->dev);
	if (!pdata) {
		dev_err(fbdev->dev, "failed to get platform data\n");
		ret = -EINVAL;
		goto err_pdata;
	}

	fbdev->lcd = (struct s3cfb_lcd *)pdata->lcd;

	if (pdata->cfg_gpio)
		pdata->cfg_gpio(pdev);

	if (pdata->clk_on)
		pdata->clk_on(pdev, &fbdev->clock);

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res) {
		dev_err(fbdev->dev, "failed to get io memory region\n");
		ret = -EINVAL;
		goto err_io;
	}

	res = request_mem_region(res->start,
				 res->end - res->start + 1, pdev->name);
	if (!res) {
		dev_err(fbdev->dev, "failed to request io memory region\n");
		ret = -EINVAL;
		goto err_io;
	}

	fbdev->regs = ioremap(res->start, res->end - res->start + 1);
	if (!fbdev->regs) {
		dev_err(fbdev->dev, "failed to remap io region\n");
		ret = -EINVAL;
		goto err_mem;
	}

	s3cfb_set_vsync_interrupt(fbdev, 1);
	s3cfb_set_global_interrupt(fbdev, 1);
	s3cfb_init_global(fbdev);

	if (s3cfb_alloc_framebuffer(fbdev)) {
		ret = -ENOMEM;
		goto err_alloc;
	}

	if (s3cfb_register_framebuffer(fbdev)) {
		ret = -EINVAL;
		goto err_register;
	}

	s3cfb_set_clock(fbdev);
	s3cfb_set_window(fbdev, pdata->default_win, 1);

	s3cfb_display_on(fbdev);

	fbdev->irq = platform_get_irq(pdev, 0);
	if (request_irq(fbdev->irq, s3cfb_irq_frame, IRQF_SHARED,
			pdev->name, fbdev)) {
		dev_err(fbdev->dev, "request_irq failed\n");
		ret = -EINVAL;
		goto err_irq;
	}

#ifdef CONFIG_FB_S3C_LCD_INIT
	if (pdata->backlight_on)
		pdata->backlight_on(pdev);

	if (!bootloaderfb && pdata->reset_lcd)
		pdata->reset_lcd(pdev);
#endif

#ifdef CONFIG_HAS_EARLYSUSPEND
	fbdev->early_suspend.suspend = s3cfb_early_suspend;
	fbdev->early_suspend.resume = s3cfb_late_resume;
	fbdev->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
	register_early_suspend(&fbdev->early_suspend);
#endif

	ret = device_create_file(&(pdev->dev), &dev_attr_win_power);
	if (ret < 0)
		dev_err(fbdev->dev, "failed to add sysfs entries\n");

	dev_info(fbdev->dev, "registered successfully\n");

#if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO)
	if (fb_prepare_logo( fbdev->fb[pdata->default_win], FB_ROTATE_UR)) {
		printk("Start display and show logo\n");
		/* Start display and show logo on boot */
		fb_set_cmap(&fbdev->fb[pdata->default_win]->cmap, \
                                            fbdev->fb[pdata->default_win]);
		fb_show_logo(fbdev->fb[pdata->default_win], FB_ROTATE_UR);
	}
#endif
	mdelay(100);
	if (pdata->backlight_on)
		pdata->backlight_on(pdev);

	return 0;

err_irq:
	s3cfb_display_off(fbdev);
	s3cfb_set_window(fbdev, pdata->default_win, 0);
	for (i = pdata->default_win;
			i < pdata->nr_wins + pdata->default_win; i++) {
		j = i % pdata->nr_wins;
		unregister_framebuffer(fbdev->fb[j]);
	}
err_register:
	for (i = 0; i < pdata->nr_wins; i++) {
		if (i == pdata->default_win)
			s3cfb_unmap_default_video_memory(fbdev->fb[i]);
		framebuffer_release(fbdev->fb[i]);
	}
	kfree(fbdev->fb);

err_alloc:
	iounmap(fbdev->regs);

err_mem:
	release_mem_region(res->start,
				 res->end - res->start + 1);

err_io:
	pdata->clk_off(pdev, &fbdev->clock);

err_pdata:
	regulator_disable(fbdev->regulator);

err_regulator:
	kfree(fbdev);

err_global:
	return ret;
}

(1)struct s3c_platform_fb 结构体

这个结构体是fb的platform_data结构体,这个结构体变量就是platform设备的私有数据,这个数据在platform_device.device.platform_data中存储。在mach文件中去准备并填充这些数据,在probe函数中通过传参的platform_device指针取出来。

(2)struct s3cfb_global 结构体

在具体操作层的两个文件(s3cfb.c和s3cfb_fimd6x.c)的函数中传递数据。

(3)struct resource 结构体


(4)struct regulator 结构体


(5)platform_data的传递过程

1)to_fb_plat

2)s3cfb_set_platdata

3)smdkc110_machine_init

4)struct s3cfb_lcd

5)pdata->cfg_gpio

6)pdata->clk_on


(6)resource的处理

板级文件mach-x210.c中提供resource结构体数组,s3cfb_probe()函数的platform_get_resource函数取出resource并且按FLAG分头处理。

(7)一些硬件操作

1)s3cfb_set_vsync_interrupt
2)s3cfb_set_global_interrupt


(8)s3cfb_init_global


(9)向框架注册该fb设备

1)s3cfb_alloc_framebuffer

2)s3cfb_register_framebuffer


(10)一些硬件操作
1)s3cfb_set_clock

2)s3cfb_set_window

3)s3cfb_display_on

(11)驱动中处理中断

1)platform_get_irq

2)request_irq

(12)logo显示

fb_show_logo
(13)backlight点亮

 

5、更多分析

与LCD有关的更多内容,参见以下博客:

修改内核的启动logo_天糊土的博客-CSDN博客

应用层为何不能设置分辨率_天糊土的博客-CSDN博客

相关文章

学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习...
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面...
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生...
Can’t connect to local MySQL server through socket \'/v...
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 ...
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服...