Linux 将所有外部设备看成是一类特殊文件,称之为“设备文件”,如果说系统调用是Linux内核和应用程序之间的接口,那么设备驱动程序则可以看成是 Linux 内核与外部设备之间的接口。设备驱动程序向应用程序屏蔽了硬件在实现上的细节,使得应用程序可以像操作普通文件一样来操作外部设备。 1. 字符设备和块设备 Linux 抽象了对硬件的处理,所有的硬件设备都可以像普通文件一样来看待:它们可以使用和操作文件相同的、标准的系统调用接口来完成打开、关闭、读写和 I/O 控制操作,而驱动程序的主要任务也就是要实现这些系统调用函数。Linux 系统中的所有硬件设备都使用一个特殊的设备文件来表示,例如,系统中的第 一个 IDE 硬盘使用/dev/hda 表示。每个设备文件对应有两个设备号:一个是主设备号,标识该设备的种类,也标识了该设备所使用的驱动程序;另一个是 次设备号,标识使用同一设备驱动程序的不同硬件设备。设备文件的主设备号必须与设备驱动程序在登录该设备时申请的主设备号一致,否则用户进程将无法访问到 设备驱动程序。 在Linux 操作系统下有两类主要的设备文件:一类是字符设备,另一类则是块设备。字符设备是以字节为单位逐个进行 I/O 操作的设备,在对字符设备发出读 写请求时,实际的硬件I/O 紧接着就发生了,一般来说字符设备中的缓存是可有可无的,而且也不支持随机访问。块设备则是利用一块系统内存作为缓冲区,当用 户进程对设备进行读写请求时,驱动程序先查看缓冲区中的内容,如果缓冲区中的数据能满足用户的要求就返回相应的数据,否则就调用相应的请求函数来进行实际 的I/O 操作。块设备主要是针对磁盘等慢速设备设计的,其目的是避免耗费过多的CPU 时间来等待操作的完成。一般说来,PCI 卡通常都属于字符设备。 2. 设备驱动程序接口 Linux 中的I/O 子系统向内核中的其他部分提供了一个统一的标准设备接口,这是通过include/linux/fs.h 中的数据结构 file_operations 来完成的: struct file_operations { struct module *owner; loff_t (*llseek) (struct file *, loff_t, int); ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t); ssize_t (*aio_...