Linux设备驱动属于内核的一部分,Linux内核的一个模块可以以两种方式被编译和加载:
(1)直接编译进Linux内核,随同Linux启动时加载。
(2)编译成一个可加载和删除的模块。
驱动程序向内核添加了一些函数,是内核的一部分。例如Open(), Release(), Read(), Write()。这些函数由内核在适当的时候来调用,可以用来完成硬件访问等操作。驱动程序占kernel源代码超过50%。
内核中printk()函数的设计目的并不是为了和用户交流,它实际上是内核的一种日志机制,用来记录下日志信息或者给出警告提示。如果syslogd 和klogd 守护进程在运行的话,则不管是否向控制台输出,消息都会被追加进/var/log/messages 文件。klogd只处理内核消息,syslogd 处理其他系统消息,比如应用程序。
设备驱动的并发控制
自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环查看是否该自旋锁的保持者已经释放了锁,“自旋”就是“在原地打转”。自旋锁适合于保持时间非常短的情况,它可以在任何上下文使用。
信号量则引起调用者睡眠,它把进程从运行队列上拖出去,除非获得锁。信号量适合于保持时间较长的情况,会只能在进程上下文使用。
如果被保护的共享资源需要在中断上下文访问(包括底半部即中断处理句柄和顶半部即软中断),就必须使用自旋锁。
设备驱动的内存与IO访问
内核虚拟内存映射到连续的物理内存。
CPU 通常并没有为这些已知的外设I/O内存资源的物理地址预定义虚拟地址范围,驱动程序并不能直接通过物理地址访问I/O 内存资源,而必须将它们映射到核心虚地址空间内(通过页表),然后才能根据映射所得到的核心虚地址范围,通过访内指令访问这些I/O内存资源。Linux 在io.h 头文件中声明了函数ioremap(),用来将I/O 内存资源的物理地址映射到核心虚地址空间(3GB-4GB)。
驱动中使用的地址是虚拟地址。外设的IO地址需要映射到虚拟地址。
Linux设备驱动需要使用内核API来实现,被包含在Linux内核源码树中。驱
动可以编译到内核,随着内核一起在系统启动的时候被加载,可以编译成内核模块,在系统运行起来之后动态地加载到内核中,使得调试的时候无需重新编译内核,也无需重启系统,很大程度上方便了驱动代码的调试。
但并不是只有设备驱动才能编译成模块,有些内核功能的实现也可以,以便在需要的时候再加载,比如内核中文件系统的实现、加密及校验的实现、网络协议栈的实现等等。
关注私聊小优了解更多it资讯和免费公开课~~