linux设备驱动学习总结-keyPoints

1、linux设备模型把linux驱动分为三部分:总线、设备、驱动,设备与驱动相对独立,由总线负责设备和驱动的匹配,设备注册匹配驱动,驱动注册匹配设备。

2、linux内核充分体现了面向对象的思想,为了实现高内聚,低耦合的软件模型,linux驱动尽量的把独立的功能模块分离出来,分离的手段是通过分层,比如设备和驱动分出一个总线层,做到了设备和驱动的分离;分出一个input层,做到了输入设备和文件操作(file_ops)的分层;I2c分出一个核心层,做到了I2c adapter和I2c client的分离。类似的案例在linux驱动中比比皆是。这样做的好处是,降低了程序的耦合,提高了驱动程序的可移植性。

3、对于依附在所有总线(platform总线,I2c总线,spi总线等等)的设备驱动而言,他们有一些固定的特性,比如他们都有一个xxx_driver的结构体,platform总线上的设备驱动有platform_driver结构,I2C总线上的设备驱动有i2c_driver,spi总线上的设备驱动有spi_driver结构,这些结构的内容也基本大同小异,提供了probe,remove,suspend,resume的接口,同时会提供一个device_driver的结构体实例成员,这个结构体成员描述了xxx_driver(xxx是总线名字)在驱动意义上的一些共性,它里面有一个bus_type的成员用来描述总线属性,一般这个结构会在总线设备层被实例化,比如platform定义了platform_bus_type,正式有了这个bus_type,所有驱动能和总线,以及依附与总线上的设备关联起来。以依附在platform总线上的设备驱动为例,有如下代码:

bus_type的实例的match函数指针,指定了该总线上设备和驱动的匹配规则。

4、在2.6版本以及之前版本内核,对设备的描述都是用c语言实现的,存储在/kernel_source/arch/plat/mach_xxxx目录下。3.x之后,对设备的描述体现在设备树文件,原来的板级文件不再使用,但是设备的基本结构没有变化,只是由内核负责读取fdt(flattened device tree),然后展开成2.6版本同样的结构,可以称为edt(expanded device tree)。

5、在sysfs下的各个目录都有该设备的可读写属性,比如/sys/class/graphics/fb0/bits_per_pixel文件,可以用来读取、设置液晶屏的位深属性。这个文件的生成跟attribute结构体紧密相连,代码如下: 

从上面的代码可以看出,内核还是很面向对象的,类似C++的继承。

事实上,sysfs中的目录来源于bus_type、device_driver、device,而目录中的文件则来源与attribute。Linux内核中也定义了一些快捷方式以方便attribute结构的创建工作。

6、下面的这段代码可以遍历整个sysfs,并且dump出来总线、设备、和驱动信息,如果去掉#注释,还可以为整个系统中的设备建立/dev下的设备节点

7、linux产生竞态主要三种情况:中断、抢占、多处理器。一个cpu运行在进程上下文或者中断上下文(且这段上下文是临界区域)的时候可能被中断打断;被其它进程抢占;或者其它的cpu也要访问临界区域。这个时候就会发生竞态。

8、linux下产生竞态主要有中断、抢占、多处理器这三种情况。避免中断产生的竞态,可以提前关闭中断,处理完成后在开启中断;避免抢占产生的竞态,可以使用spin_lock,因为自旋锁锁住的临界区域是不可抢占的,但是要求临界区域尽量的短。另外在关闭中断的情况下抢占的竞态也不会发生,因为linux内核的进程调度也依赖中断实现;针对多处理器产生的竞态,通常也是使用spin_lock,或者互斥锁也可以,至于什么时候使用互斥锁,什么时候使用自旋锁,参考第11条。(另外2.6.35后,取消了中断嵌套,所以中断与中断产生的竞态可以不用担心了)

9、针对前两条,做一个情景分析。假如cpu运行在中断上下文,中断和抢占产生的竞态都不需要考虑,因为,2.6.35后,中断嵌套被取消,且中断上下文的优先级要高于进程上下文(抢占本身是进程抢占,运行在进程上下文),需要考虑的是多处理器产生的竞态,参考上一条,多处理器产生的竞态可以用spin_lock或者互斥锁来避免,但是中断不允许睡眠(互斥锁在拿不到锁的情况下会进入睡眠)所以必须使用spin_lock;假如cpu运行在进程上下文,则中断、抢占、多处理器这三种情况都需要考虑,避免竞态的办法参考上一条。

10、spin_lock在单处理器的情况下,自动退化为互斥锁(宋宝华说的,不知道是不是真的这样)。而实际上,spin_lock在单处理器情况下没有任何意义,想象一下单处理器运行在进程上下文,spin_lock锁住的区域可能产生竞态的情况只有中断,如果中断中也要访问这段临界区域,假如中断拿不到锁,那就彻底挂了(因为他会自旋,且我们只有一个cpu),如果顺利拿到锁,说实在的在单处理器中没有任何意义。

11、什么情况下用自旋锁,什么情况下用互斥锁?

首先,在临界区较小,占用cpu时间较短,或者任务的实时性要求较高的情况下使用自旋锁,可避免CPU频繁调度产生的开销。

其次,有可能引起阻塞的临界区绝对不可以使用自旋锁,阻塞意味着进程切换,切换到的进程如果也要spin_lock加锁,死锁就产生了。

最后,在中断和软中断中的临界区域,尽量使用自旋锁(这种情况也符合第一条,因为中断是实时性要求较高的任务),如果一定要用互斥锁,也要try_lock,因为中断程序不能睡眠。


持续补充中........

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章