linux驱动开发详解————宋宝华 笔记
1.udev负责捕获内核发送的uevent事件,进行规则匹配生成删除设备文件,比devfs区别是将设备的增加删除交给应用程序,而不是给内核
2.字符设备驱动cdev_add()函数和cdev_del()函数分别向系统添加和删除一个cdev,完成字符设备的注册和注销,在字符设备驱动模块加载函数中应该实现设备号的申请和cdev的注册,而在卸载函数中应实现设备号的释放和cdev的注销。
3.file_operations结构体中的成员函数是字符设备驱动与内核虚拟文件系统的接口,由于用户空间不能直接访问内核空间的内存,因此借助了函数copy_from_user()完成用户空间缓冲区到内核空间的复制,以及
copy_to_user()完成内核空间到用户空间缓冲区的复制
4.访问共享资源的代码区域称为临界区(Critical Sections),临界区需要被以某种互斥机制加以保护。中断屏蔽、原子操作、自旋锁、
信号量、互斥体等是Linux设备驱动中可采用的互斥途径。
5.在自旋锁锁定期间不能调用可能引起进程调度的函数。如果进程获得自旋锁之后再阻塞,如调用copy_from_user()、
copy_to_user()、kmalloc()和msleep()等函数,则可能导致内核的崩溃。
6.互斥体是进程级的,用于多个进程之间对资源的互斥,虽然也是在内核中,但是该内核执行路径是以进程的身
份,代表进程来争夺资源的。如果竞争失败,会发生进程上下文切换,当前进程进入睡眠状态,CPU将运行其
他进程。鉴于进程上下文切换的开销也很大,因此,只有当进程占用资源时间较长时,用互斥体才是较好的选
择。当所要保护的临界区访问时间比较短时,用自旋锁是非常方便的,因为它可节省上下文切换的时间。但是CPU
得不到自旋锁会在那里空转直到其他执行单元解锁为止,所以要求锁不能在临界区里长时间停留,否则会降低
系统的效率。
7. 由此,可以总结出自旋锁和互斥体选用的3项原则。
1)当锁不能被获取到时,使用互斥体的开销是进程上下文切换时间,使用自旋锁的开销是等待获取自旋锁(由
临界区执行时间决定)。若临界区比较小,宜使用自旋锁,若临界区很大,应使用互斥体。
2)互斥体所保护的临界区可包含可能引起阻塞的代码,而自旋锁则绝对要避免用来保护包含这样代码的临界
区。因为阻塞意味着要进行进程的切换,如果进程被切换出去后,另一个进程企图获取本自旋锁,死锁就会发
生。
3)互斥体存在于进程上下文,因此,如果被保护的共享资源需要在中断或软中断情况下使用,则在互斥体和自
旋锁之间只能选择自旋锁。当然,如果一定要使用互斥体,则只能通过mutex_trylock()方式进行,不能获取就
立即返回以避免阻塞
8 并发和竞态广泛存在,中断屏蔽、原子操作、自旋锁和互斥体都是解决并发问题的机制。中断屏蔽很少单独被
使用,原子操作只能针对整数进行,因此自旋锁和互斥体应用最为广泛。
自旋锁会导致死循环,锁定期间不允许阻塞,因此要求锁定的临界区小。互斥体允许临界区阻塞,可以适用于
临界区大的情况。
10.Linux设备中的并发控制有中断屏蔽、原子操作、自旋锁、读写锁、RCU锁、互斥量;
11.通常会使用select()和poll()系统调用查询是否可对设备进行无阻塞的访问,select()和poll()系统调用的本质一样,前者在BSD UNIX中引入,后者在System V中引入.
当多路复用的文件数量庞大、I/O流量频繁的时候,一般不太适合使用select()和poll(),此种情况下,select()和poll()的
性能表现较差,我们宜使用epoll。epoll的最大好处是不会随着fd的数目增长而降低效率,select()则会随着fd的数量增大性能下
降明显。
12.Linux中的异步I/O:使用信号可以实现设备驱动与用户程序之间的异步通知,总体而言,设备驱动和用户空间要分别完成3项对应的
工作,用户空间设置文件的拥有者、FASYNC标志及捕获信号,内核空间响应对文件的拥有者、FASYNC标志的
设置并在资源可获得时释放信号。
13.在Linux 2.6以后的设备驱动模型中,需关心总线、设备和驱动这3个实体,总线将设备和驱动绑定。在系统每注
册一个设备的时候,会寻找与之匹配的驱动;相反的,在系统每注册一个驱动的时候,会寻找与之匹配的设
备,而匹配由总线完成
14.现在我们将前面章节的globalfifo驱动挂接到platform总线上,这要完成两个工作。
1)将globalfifo移植为platform驱动。注册完globalfifo对应的platform_driver后,我们会发现/sys/bus/platform/drivers目录下多出了一个名字叫globalfifo的子目录。
static struct platform_driver globalfifo_driver = {
.driver = {
.name = "globalfifo",
.owner = THIS_MODULE,
},
.probe = globalfifo_probe,
.remove = globalfifo_remove,
};
2)在板文件中添加globalfifo这个platform设备。会在/sys/devices/platform目录下看到一个名字叫globalfifo的子目录,/sys/devices/platform/globalfifo中会有一个driver文件,它是指向/sys/bus/platform/drivers/globalfifo的符号链接,
static struct platform_device globalfifo_device = {
.name = "globalfifo",
.id = -1,
};
linux驱动开发详解——宋宝华 笔记
最新推荐文章于 2024-05-16 08:30:00 发布