学习目标:
了解Linux系统中驱动程序的概念、作用,为后续学习驱动程序编写打下基础!
U-boot的目的是启动内核,内核的目的是启动应用程序。应用程序中可能会涉及到读写文件、点亮LED、获取按键值等操作,而对于写应用程序的人来说不必去关心具体硬件如何操作,仅仅只调用open、rend、write等标准接口,便可完成上述一些功能。应用程序里使用open、read、write等标准接口函数,其实就是去调用驱动程序,完成底层硬件操作。
以点亮一个LED为例说明,最简单的对应方法是:应用程序中有open函数,对应LED驱动程序中也有led_open;应用程序中有write函数,对应LED驱动程序中也有led_write;应用程序中有read函数,对应LED驱动程序中也有led_read函数。应用程序通过read函数读取LED状态时,调用驱动函数led_read实现读取LED状态目的,通过write函数改变LED状态时,调用驱动函数led_write改变LED状态。
下面来介绍应用程序open、read、write等标准接口函数,最终如何调用到驱动程序中的led_open、led_read、led_write,中间有哪些东西。
从上到下,一个软件系统可以分为:应用程序、库、内核、驱动程序。开发人员可以专注于自己熟悉的部分,对于相邻层,只需要了解它的接口,无需关注它的实现细节。linux中这4层的协作关系如下图所示:
假设上图的App1是源码如下所示的简单应用程序:
1 int main() 2 { 3 int fd1,fd2; 4 int val = 1; 5 6 fd1 = open("/dev/led",ORDWR); 7 write(fd1,&val,4); 8 9 fd2 = open("hello.txt",ORDWR); 10 write(fd2,&val,4); 11 }
- ①App1中应用程序调用open(read、write)函数打开相应设备文件,这些函数在C库中实现。
- ②库函数根据open函数传入的参数执行“swi”指令,这条指令会引起CPU异常,进入内核空间。
- ③内核异常空间处理函数根据这些传入不同参数去调用System call interface中sys_open,这些函数根据打开不同文件的属性找到更底层驱动程序。例如App1代码中open函数根据打开文件不同属性,分别去调用LED灯的驱动程序和存储器的驱动程序。
从上面操作可以知道,驱动程序和应用程序不同,驱动程序从不主动运行,它是被动加载的:根据应用程序的要求进行初始化,,根据应用程度的要求进行读写。驱动程序加载进内核时,只是告诉内核“我在这里,我能做这些工作”,至于这些“工作”何时开始,取决于应用程序。
内核和驱动程序之间没有界限,因为驱动程序最终是要编进内核去的:通过静态链接或者动态加载。