openwrt之字符设备驱动开发

第二章 字符设备驱动开发及相关概念

应用程序、库、内核、驱动程序的关系

关系示意图]

以驱动LED为例:

  1. 应用程序使用库提供的 open 函数打开代表 LED 的设备文件。
  2. 库根据 open 函数传入的参数执行SWI指令,该指令会引起 CPU 异常,进入内核。
  3. 内核的异常处理函数根据这些参数找到相应的驱动程序,返回一个文件句柄给库, 进而返回给应用程序
  4. 应用程序得到文件句柄后,使用库提供的 write 或 ioclt 函数发出控制命令。
  5. 库根据 write 和 ioclt 函数传人的参数执行 swi 指令, 这条指令会引起 CPU 异常,进入内核。
  6. 内核的异常处理函数根据这些参数调用驱动程序的相关函数,点亮 LED。

在异常处理函数中,内核会根据传入的参数执行各种操作,比如根据设备文件名找到对应的驱动程序,调用驱动程序的相关函数等。一般来说,当应用程序调用 open、read、write、ioctl、mmap 等函数后,将会使用驱动程序中的 open、read、write、ioctl、mmap 函数来执行相关操作,比如初始化、读、写等。实际上,内核和驱动程序之间并没有界线,因为驱动程序最终是要编进内核去的:通过静态链接和动态加载。

Linux 驱动程序分类

1. 字符设备

字符设备是能够像字节流(比如文件)一样被访问的设备,就是说对它的读写是以字节为单位的。字符设备的驱动程序中实现了 open、close、read、write 等系统调用,应用程序可以通过设备文件(比如/dev/ttySAC0 等)来访问字符设备。

2. 块设备

块设备上的数据以块的形式存放,比如 NAND Flash 上的数据就是以页为单位存放的。块设备驱动程序向用户层提供的接口与字符设备一样,应用程序也可以通过相应的设备文件(如/dev/mtdblock0/dev/hda1 等)来调用 open、close、read、write 等系统调用,与块设备传送任意字节的数据。对用户而言,字符设备和块设备的访问方式没有差别。块设备驱动程序的特别之处如下:

  • 操作硬件的接口实现方式不一样。 块设备驱动程序先将用户发来的数据组织成块,再写入设备;或从设备中读出若干块数据,再从中挑出用户需要的。
  • 数据块上的数据可以有一定的格式,不同的文件系统类型就是用来定义这些格式的。内核中,文件系统的层次位于块设备驱动程序上面,这意味着块设备驱动程序除了向用户层提供与字符设备一样的接口外,还要向内核其他部件提供一些接口,这些接口用户是看不到的。这些接口使得可以在块设备上存放文件系统,挂载块设备。
3. 网络接口

网络接口同时具有字符设备、块设备的部分特点,无法将它归入这两类中:如果说它是字符设备,他的输入/输出却是有结构的、成块的(报文、包、帧);如果说它是块设备, 它的块又不是固定大小的,大到数百甚至数千字节,小到几字节。UNIX 式的操作系统访问网络接口的方法是给它们分配一个惟一的名字(比如 eth0),但这个名字在文件系统中(比如/dev 目录下)不存在对应的节点项。应用程序、内核和网络驱动程序间的通信完全不同于字符设备、块设备,库、内核提供了一套和数据包传输相关的函数,而不是 open、 read、write 等。

Linux 驱动程序开发步骤

Linux 内核就是由各种驱动组成的,内核源码中有大约 85% 是各种驱动程序的代码。一般来说,编写一个 Linux 设备驱动程序的大致流程如下:
- 查看原理图、数据手册,了解设备的操作方法。
- 在内核中找到相近的驱动程序,以它为模板进行开发,有时候需要从零开始。
- 实现驱动程序的初始化:如向内核注册这个驱动,应用程序传入文件名时内核才能找到相应的驱动程序。
- 设计所要实现的操作,比如 open、close、read、write 等函数。
- 实现中断服务(中断并不是每个设备驱动所必须的)。
- 编译该驱动程序到内核中,或者用 insmod 命令加载。
- 测试驱动程序。

驱动程序的加载和卸载

可以将驱动程序静态编译进内核中,也可以将它作为模块在使用时再加载。在配置内核时,如果某个配置选项被设为 m,就表示它将会被编译成一个模块。在 2.6 的内核中,模块的扩展名为.ko,可以使用 insmod 命令加载,使用 rmmod 命令卸载,使用 lsmod 命令查看内核中已经加载了哪些模块。 当使用 insmod 加载模块时,模块的初始化函数被调用,它用来向内核注册驱动程序。当使用 rmmod 卸载模块时,模块的清除函数被调用。

在驱动代码中,这两个函数要么取固定的名字:init_modulecleanup_module,要么使用以下两行来标记它们(假设初始化函数、清除函数为my_initmy_cleanup)

moudle_init(my_init); 
module_exit(my_cleanup);

猜你喜欢

转载自blog.csdn.net/robothj/article/details/80036127
今日推荐