驱动之LCD驱动框架和实现
总览
- 嵌入式linux学习目录
- 驱动之input子系统
- 驱动之platform概念
- 驱动之RTC分析
- 驱动之LCD驱动框架和实现
- 驱动之触摸屏驱动框架和实现
- 驱动之USB基础概念和框架
- 驱动之USB设备驱动程序
本文使用 linux-2.6.22.6 内核, 使用jz2440开发板.
LCD驱动框架分析
字符驱动基本步骤
根据之前写的驱动, 已经对linux驱动基本步骤比较熟悉了.
- 所有的驱动都会调用
module_init
和module_exit
, 从module_init
开始看比较好. - 定义并设置
file_operations
结构体, 然后实现里面的函数, 如open等. - 获取
主设备号
, 可以手动分配, 也可以由系统自动分配 - 用
register_chrdev
注册字符设备. 核心过程如下:__register_chrdev_region
注册/申请主设备号, 并申请子设备号范围.cdev_init
用file_operations
结构体初始化一个字符设备cdev_add
用设备号向系统添加字符设备.
- 如果要用mdev自动加载驱动, 还需要在init里实现如下函数
class_create
, 创建一个设备类. 可以在/sys/class/
看到设备类名称device_create
, 创建和注册设备. 可以在/dev/
看到设备名称class_device_create
是低版本Linux的函数. 本质就是device_create
LCD驱动框架分析
Linux的LCD驱动用了分层分离的思想, 用到了platform框架.
/drivers/video/fbmem.c
frame buffer memory, 显存操作相关subsys_initcall(fbmem_init);
fbmem的初始化.register_chrdev(FB_MAJOR,"fb",&fb_fops)
注册字符设备,fb_class = class_create(THIS_MODULE, "graphics");
注册 graphics 设备类- 可以去
/sys/class/graphics
看看, 下面有 fb0 和 fbcon 两个文件. - 这里没有注册设备, 因为视频控制器和具体硬件相关
registered_fb
是具体设备给fbmem.c提供信息的关键!fb_read
fb_write
里都可以看到struct fb_info *info = registered_fb[fbidx];
- 然后, 函数根据 info 信息, 决定是进一步调用具体设备的 read write等函数, 还是使用默认代码.
register_framebuffer(struct fb_info *fb_info)
供LCD设备调用, 提交registered_fb
信息并注册设备.device_create(fb_class, fb_info->device, MKDEV(FB_MAJOR, i), "fb%d", i)
- 真正注册一个LCD设备, 名字是fb0, fb1这样递加上去. 可以在
/dev/
里找到.
/drviers/video/s3c2410fb.c
具体硬件的LCD驱动.- 这里用到了platform框架.
s3c2410fb.c
是硬件相关的通用操作, 属于platform_driver
module_init
里, 直接就是platform_driver_register
.- 我们知道platform框架里,
probe
函数是很关键的, 在drive和device匹配时, 就会调用它. probe
函数里, 初始化后, 可看到register_framebuffer(fbinfo);
将LCD设备信息提交给fbmem.c, 并注册设备.
- 这里用到了platform框架.
/arch/arm/mach-s3c2440/mach-smdk2440.c
配置硬件参数的地方.- 这里是platform框架的
platform_device
. smdk2440_machine_init
初始化里s3c24xx_fb_set_platdata(&smdk2440_lcd_cfg);
将LCD配置信息拷贝到s3c_device_lcd
platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));
注册 platform_device 设备.smdk2440_devices
里就包含了s3c_device_lcd
- 如果硬件平台不变, 只是换屏的话, 只需要修改
mach-smdk2440.c
即可. 这就是分层分离概念的意义所在.
- 这里是platform框架的
补充说明 fbmem.c
的上层:
/drivers/video/console/fbcon.c
在lcd上显示终端, 此文件和tty1关联.class_device_create(fb_class, NULL, MKDEV(0, 0), NULL, "fbcon");
注册fbcon
设备fbcon_start
和 fb设备对接, 开始显示.
- app层调用
open("/dev/fb0", ...)
, 主设备号为29, 次设备号为0- 会对应到kernel层
fbmem.c
的fb_open
函数: int fbidx = iminor(inode);
struct fb_info *info = = registered_fb[0];
- 会对应到kernel层
- app层调用
read()
- 会对应到kernel层
fbmem.c
的fb_read
函数: registered_fb
由register_framebuffer
设置.
- 会对应到kernel层
fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { |
LCD驱动源码
现在尝试忽略 /drviers/video/s3c2410fb.c
使用的platform框架.
直接自己写一个 LCD 驱动, 和 /drivers/video/fbmem.c
进行对接.
此处只是为了练习, 实际项目不建议这样使用
驱动的核心步骤如下:
- 分配一个fb_info:
s3c_lcd = framebuffer_alloc(0, NULL);
- 设置fb_info
2.1 设置固定的参数,struct fb_fix_screeninfo
2.2 设置可变的参数,struct fb_var_screeninfo
2.3 设置操作函数,fbops
2.4 其他的设置 - 硬件相关的操作
3.1 配置GPIO用于LCD
3.2 根据LCD手册设置LCD控制器, 比如VCLK的频率等
3.3 分配显存(framebuffer), 并把地址告诉LCD控制器 - 注册
register_framebuffer(s3c_lcd);
测试, 原系统
在使用自己写的LCD驱动源码之前, 先用系统提供的LCD框架驱动测试一下显示屏
# 开发板端 |
lcd.c
|
Makefile
obj-m := lcd.o |
测试
这个测试比较复杂, 需要去掉自带的LCD驱动, 重新编译和烧录内核.
# Ubuntu 主机端 |
参考资料
原创于 DRA&PHO