lcd驱动源码分析(s3cfb.c)(代码片段)

正在起飞的蜗牛 正在起飞的蜗牛     2023-03-12     794

关键词:

1、驱动源码分析大致思路

(1)分析LCD驱动首先需要分析内核的帧缓冲子系统,因为LCD驱动就是按照帧缓冲子系统提供的注册接口来注册的;
(2)内核帧缓冲子系统参考博客:《Linux 帧缓冲子系统详解:LCD介绍、framebuffer驱动框架、LCD驱动源码分析》
(3)先分析LCD驱动的加载和卸载;
(4)梳理清楚应用是如果调用到LCD驱动的;
(5)LCD驱动的源码大致分为两部分:一部分是Soc的LCD控制器,一方面是LCD本身,两者都是去查阅数据手册;
(6)LCD和Soc是通过gpio口连接的,分析LCD源码还涉及内核的gpio子系统,参考博客:《2.6.35内核的gpio子系统详解》

2、应用层、帧缓冲子系统、LCD驱动三者的联系

(1)应用层通过操作设备节点"/dev/fbn"来操作LCD屏幕;
(2)应用层操作设备节点,首先是调用到帧缓冲子系统的struct file_operations操作方法;
(3)设备节点里包含主次设备号,帧缓冲系统先根据主次设备号找到对应注册过的驱动;
(4)最后调用驱动的struct fb_ops结构体里的方法;
补充:《应用程序操作LCD源码分析》

3、LCD驱动的加载

static struct platform_driver s3cfb_driver = 
	.probe = s3cfb_probe,
	.remove = __devexit_p(s3cfb_remove),
	.driver = 
		   .name = S3CFB_NAME,
		   .owner = THIS_MODULE,
	,
;

static int __init s3cfb_register(void)

	//向platform平台总线注册驱动
	platform_driver_register(&s3cfb_driver);

	return 0;

static void __exit s3cfb_unregister(void)

	//向platform平台总线卸载驱动
	platform_driver_unregister(&s3cfb_driver);


module_init(s3cfb_register);
module_exit(s3cfb_unregister);

(1)LCD驱动是利用平台总线进行注册的,在内核启动时也会注册相应的LCD的平台设备,当驱动和设备匹配就会执行驱动的probe函数;
(2)平台总线相关知识参考博客:《内核platform总线详解:定义、注册、匹配、使用示例》

4、LCD驱动的prob函数分析

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;

	//分配s3cfb_global结构体大小的内存
	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;
	

	//获取platform设备传过来的私有数据
	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;

	//设置LCD相关的引脚
	if (pdata->cfg_gpio)
		pdata->cfg_gpio(pdev);

	//打开LCD的时钟
	if (pdata->clk_on)
		pdata->clk_on(pdev, &fbdev->clock);

	//获取设备IORESOURCE_MEM类的资源
	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;
	

	//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;
	

	//开启相关中断,是设置的LCD控制器的寄存器
	s3cfb_set_vsync_interrupt(fbdev, 1);
	s3cfb_set_global_interrupt(fbdev, 1);

	//根据设备传过来的数据,设置LCD控制器
	s3cfb_init_global(fbdev);

	//构建struct fb_info结构体
	if (s3cfb_alloc_framebuffer(fbdev)) 
		ret = -ENOMEM;
		goto err_alloc;
	

	//将struct fb_info结构体注册到帧缓冲子系统中
	if (s3cfb_register_framebuffer(fbdev)) 
		ret = -EINVAL;
		goto err_register;
	

	//设置LCD控制器的时钟
	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");

	//这是显示内核开机的logo
#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)解析出平台设备传过来的数据;
(2)设置LCD相关的gpio引脚,设置好时钟;
(3)对LCD相关的寄存器地址进行动态映射;
(4)根据平台设备传过来的数据,设置Soc的LCD控制器相关寄存器;
(5)构建struct fb_info结构体,最重要的是struct fb_ops结构体,这是LCD屏幕的具体硬件操作方法,然后注册到帧缓冲子系统中;
(6)打开默认的显示屏。一个LCD可以对应对个虚拟屏幕;
(7)给设备创建属性文件,设备属于"graphics"类,在"/sys/class/graphics"目录下可以看到;
(8)显示内核的启动logo,打开屏幕的背光,真正显示出启动logo;

10.lcd驱动程序——框架分析(代码片段)

...一副图像所需要的数据。因此,帧缓冲其实就是LCD设备的驱动程序) 一.LCD驱动程序框架根据上述思路,LinuxLCD驱动程分为两个层次,如下图所示类似于Platform平台驱动框架,也将驱动程序分为相对稳定的算法驱动,即fb总线... 查看详情

分析内核自带的lcd驱动程序\_基于imx6ull(代码片段)

分析内核自带的LCD驱动程序_基于IMX6ULL参考资料,GIT仓库里:IMX6ULL\\开发板配套资料\\datasheet\\Core_board\\CPU\\IMX6ULLRM.pdf《Chapter34EnhancedLCDInterface(eLCDIF)》IMX6ULL的LCD裸机程序IMX6ULL\\source\\03_LCD\\05_参考的裸机源码\\ 查看详情

linuxlcd驱动实验(代码片段)

目录Linux下LCD驱动简析1Framebuffer设备LCD驱动简析硬件原理图分析LCD驱动程序编写运行测试LCD屏幕基本测试设置LCD作为终端控制台LCD背光调节从LCD自动关闭解决方法LCD是很常用的一个外设,在裸机篇中我们讲解了如何编写LCD裸... 查看详情

lcd显示异常分析——撕裂(teareffect)(代码片段)

...给出这类问题的常用解决方法。本文适用范围:对象:LCD驱动调试人员硬件:带GRAM的LCD(如SPI/MCU/DSICMD屏)软件:所有嵌入式操作系统现象首先贴一张动态图,让大家能直观的 查看详情

《蓝桥杯备赛》ct117e嵌入式竞赛板lcd驱动库的使用(带完整源码)(代码片段)

...开发板为蓝桥杯CT117ERev1.1,资源只用于学习用途1.蓝桥杯LCD驱动库(官方提供)lcd.c/*程序说明:CT117E嵌入式竞赛板LCD驱动程序软件环境:KeiluVision4.10硬件环境:CT117E嵌入式竞赛板日期:2011-8-9*/#include"lcd.h"#include"fonts.h"... 查看详情

一款特殊的lcd屏幕驱动调试(代码片段)

问题分析这款LCD屏幕的有效显示区域为480*1280,但是它的timing时序却是600*1280。时序要求600*1280意味着主控需要通过物理接口输出600*1280的图像,然而LCD的背板芯片会剪裁掉左右两侧各60像素,得到480*1280的显示区域。那么我们的LCD屏幕... 查看详情

编程\_lcd驱动程序框架\_使用设备树(代码片段)

编程_LCD驱动程序框架_使用设备树参考资料,GIT仓库里:基于这个程序修改:IMX6ULL\\source\\03_LCD\\03_lcd_drv_qemu_okSTM32MP157\\source\\A7\\03_LCD\\03_lcd_drv_qemu_ok参考:内核自带的示例驱动程序Linux驱动源码:drivers/v 查看详情

最简单的lcd驱动\_基于qemu(代码片段)

最简单的LCD驱动_基于QEMU本节视频对应源码在GIT仓库中,位置如下(这2个文件是完全一样的):doc_and_source_for_drivers\\STM32MP157\\source\\A7\\03_LCD\\02_lcd_drv_qemu\\lcd_drv.c或:doc_and_source_for_drivers\\IMX6ULL\\sour 查看详情

iic驱动源码程序---stc89c52实时用pcf8591采集温度lcd显示(代码片段)

一、创建头文件i2c.h代码如下:#ifndef__I2C_H_#define__I2C_H_#include<reg52.h>sbitSCL=P2^1;sbitSDA=P2^0;voidI2cStart();//I2c启动voidI2cStop();//I2c停止unsignedcharI2cSendByte(unsignedchardat);//I2c发送字节unsignedcha 查看详情

lcd驱动分析

转自:http://blog.csdn.net/hanmengaidudu/article/details/215591531.S3C2440上LCD驱动(FrameBuffer)实例开发讲解其中的代码也可直接参考:drivers/video/s3c2410fb.c以下为转载文章,文章原地址:http://blog.csdn.net/jianyun123/archive/2010/04/24/55 查看详情

lcd驱动分析时序分析

参考:S3C2440LCD驱动(FrameBuffer)实例开发<一>    S3C2440LCD驱动(FrameBuffer)实例开发<二> 查看详情

51单片机lcd1602驱动显示(模板)+proteus(代码片段)

51单片机LCD1602驱动显示(模板)+Proteus本项目工程篇,只展示LCD1602驱动显示,不涉及其他外设驱动使用,可以作为LCD1602显示的模板移植使用。实例代码main.c#include<reg51.h>#include<LCD1602.h>voidmain( 查看详情

一个清晰的lcd驱动编写思路(附代码分析)

关注「嵌入式大杂烩」,选择「星标公众号」一起进步!来源|屋脊雀网络上配套STM32开发板有很多LCD例程,主要是TFTLCD跟OLED的。从这些例程,大家都能学会如何点亮一个LCD。但这代码都有下面这些问题:分层... 查看详情

lcd驱动端与设备端名称匹配过程分析(tiny4412)

​LCD驱动端与设备端名称匹配过程在tiny4412提供的内核下,LCD屏的平台设备名字和平台驱动名字不匹配也能驱动屏点亮,​这是怎么回事的呢?下面我们来分析这是如何实现的。​硬件平台​Cpu:exynos4412​板子:tiny4412​Linux内... 查看详情

proteus仿真51单片机+lcd1602驱动模板(代码片段)

【Proteus仿真】51单片机+LCD1602驱动模板Proteus仿真主程序/*51单片机LCD1602驱动模板*/#include<REGX52.H>#include"LCD1602.h"#include"Delay.h" 查看详情

linux驱动开发lcd(代码片段)

...关的硬件和软件集合起来,虚拟出一个fb设备,LCD驱动生成/dev/fbx的设备,应用程序通过访问/dev/fbx设备即可以访问LCD。不同分辨率的LCD屏幕eLCDIF控制器驱动代码相同,只需要修改好对应的屏幕参数。Linux内核将所... 查看详情

使用spi机制加载mysql驱动源码分析(代码片段)

...加载driver主要原因是为了实现解耦和可插拔JDK提供数据库驱动的规范(即Driver接口) 查看详情

51单片机+驱动lcd1602模板范例+proteus仿真(代码片段)

51单片机+驱动LCD1602模板范例+Proteus仿真本示例可以作为驱动LCD1602屏幕模板来调用或使用,方便移植到其他需要使用到LCD1602显示上的工程项目当中。所以示例不涉及过多其他的代码内容。主程序和驱动代码分离。工程项目目录架... 查看详情