LINUX设备驱动读书笔记新版
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
嵌入式Linux设备驱动开发读书笔记
经过第十二章的学习,我大致了解了linux设备驱动开发的意义所在,在linux 系统中设备被抽象化,系统通过调用标准的驱动接口来实现各种硬件的操作,同时,系统上层对于硬件设备的调用无需关心具体的硬件细节,系统调用设备使用文件的方式进行操作,通过这样的屏蔽,系统以标准和统一的方式去完成硬件的操作,对于硬件设备更新速度越来越快的今天,硬件的更新,只需要去更改驱动就能够实现设备的升级,而不需要去改变上层的应用软件,同时也利于上层和软件和硬件之间开发的分工和合作。
设备驱动最终被添加到内核里,与系统成为一个整体,ARM处理器的指令集与我们通常使用的PC机的X86指令集不同,ARM 的RISC指令集也可以说是一个精简版本的X86指令集,虽然没有X86指令集那么强大的功能,但是同样可以支持LINUX系统的运算,因此基于ARM的LINUX系统需要使用支持ARM指令集的编译器来进行编译,也就是ARM-GCC,在宿主机,也就是X86指令集下使用ARM-GCC编译出来的LINUX系统能够在ARM硬件系统上运行。
设备驱动程序是内核的一部分,因此驱动的稳定对系统的稳定非常重要,设备驱动程序必须为内核提供一个标准的接口,并且为了防止系统过于臃肿,对于某些系统设备驱动要求能够实时的进行加载,对于设备的更新也更加的方便,以安装的方式进行加载。
以下列举我对几种设备驱动编写的理解
1字符设备:
一般应用程序都有一个main入口点,而设备驱动却没有main函数,其实模块在调用insmod命令时会进入设备驱动的module_init函数,在该函数中注册设备,在调用rmmod函数时驱动被卸载,此时入口点为module_exit函数,他们的关系如图
设备被加载之后,系统便能够在内核中调用驱动,在LINUX内核中,dev_t 类型用来保存主设备号和次设备号,dev_t四个字节,其中12bit用于表示主设备号,其余20bit表示次设备号,使用系统函数给设备分配一个设备号,
获得这个设备号之后,便能够通过特定的系统函数来对设备进行注册,当设备成功注册之后,系统就能够通过open和release操作来打开设备和卸载设备。字符设备的操作通过文件的方式来访问,也就是read和write。
2块设备驱动
系统中有部分设备通常要以块的方式进行写入,例如FLASH,IDE硬盘,SCSI 硬盘,光驱等,这些设备跟其硬件特性有关,例如FLASH存储器一般以BLOCK 位单位,对其进行改写必须整块的擦除,然后写入修改后整个BLOCK的数据。
对块设备描述的一个重要结构体是
struct blk_dev_struct{
request_queue_t request_queue;
queue_proc *queue;
void *date;
};
其中request_queue是主体,包含了初始化之后的I/O请求队列,其后通过队列处理函数指针queue进入该程序,辅助找到特定设备的请求队列,作一些私有的操作,这个函数在初始化的时候就要定义好,并赋值给指针queue。对于块设备的读写请求通过generic_file_read()和generic_file_write()来实现。
块设备驱动的编写首先要实例化三个重要的结构体变量
(1)struct device_struct:用于指明设备名称,并且包含和字符设备一样的 file_operations结构体
(2)struct sbull_dev:用于存放设备具体信息。
(3)struct file_operations:包含于struct device_struct中,用于定义块设备内核操作函数的入口。
在这几个变量定义好之后,便可以通过
来获得主设备号,接着,通过
来注册块设备。
在块设备注册好之后,最重要的操作就是request,该操作跟底层相关,对设备的内存空间进行访问。
LCD驱动分析
嵌入式LINUX将显存抽象为Framebuffer,framebuffer好比一个存放水的水池,CUP将运算后的图像数据存放到这个水池中,而LCD驱动的任务就是将这些水池里的水投放到实际的显示器中,真正往LCD的物理显存中写入数据的操作由LCD驱动完成,视频设备通用被抽象为一个文件,一般在/dev/fb0、/dev/fb1等,通过将Framebuffer映射到进程地址空间的方式来使用
了解了系统对LCD的操作,下面开始分析LCD驱动的实现
首先要获得系统定义的标准LCD设备驱动结构体,用于取得相关的操作。
从LCD驱动的入口点开始分析
S3c2410fb_init
该函数是系统注册LCD设备时调用的函数
S3c2410fb_cleanup这个函数完成LCD设备的注销,这里调用了framebuffer的注销函数,并且调用release_mem_region函数释放IO端口。
S3c2410fb_probe 是非常重要的一个函数,它完成设备硬件初始化,检测校验,创建LCD设备对象等任务。
S3c2410fb_suspend函数将LCD设备挂起,比如系统进入休眠或者待机模式,将LCD设备挂起有利于实现低功耗给移动设备节省电能
S3c2410fb_stop_lcd函数实际上是将LCD的一些中断进行屏蔽,并且重新映射空间的资源信息
S3c2410fb_resume函数主要用于将LCD设备重新开启,把设备从suspend的状态转换到激活状态
最后,将LCD驱动添加到内核中编译,再到ARM开发板上运行加载驱动模块,实现LCD的显示。
LCD驱动的工作实际上非常简单,CPU把图像数据放到Framebuffer中,对于CPU来说framebuffer就是他的显示器,CPU不用关心这些数据怎么被显示到LCD上,将显示数据搬运到LCD中实际上是由LCD驱动去完成的,在s3c2440处理器中自带LCD控制器,这种LCD控制器具有LCD驱动的标准接口,并且通过完成相关的LCD寄存器配置就能够实现不同分辨率,色深,刷新率的显示效果,LCD控制器通过DMA通道直接从framebuffer的内存区域搬运数据到LCD 显示屏中,无需占用太多的CPU时间,占用的仅仅是总线贷款而已,因此LCD 驱动的主要任务就是从系统获得相关的配置信息,经过计算来配置LCD控制器的寄存器,从而实现具体的显示任务。(*^__^*) 嘻嘻……