doyouhaveIET 2011-03-29
参考:《linux设备驱动程序》第三版
下载在安科网的1号FTP服务器里,下载地址:
密码:www.muu.cc
下载方法见 http://www.linuxidc.net/thread-1187-1-1.html
一 Linux设备驱动的基本概念
系统调用是操作系统内核和应用程序之间的接口,设备驱动程序是操作系统内核和机器硬件之间的接口。设备驱动程序为应用程序屏蔽了硬件的细节,这样在应用程序看来,硬件设备只是一个设备文件,应用程序可以象操作普通文件一样对硬件设备进行操作。设备驱动程序是内核的一部分,它完成以下的功能:
1、对设备初始化和释放;
2、把数据从内核传送到硬件和从硬件读取数据;
3、读取应用程序传送给设备文件的数据和回送应用程序请求的数据;
4、检测和处理设备出现的错误。
在Linux操作系统下有三类主要的设备文件类型,一是字符设备,二是块设备,三是网络设备。字符设备和块设备的主要区别是:在对字符设备发出读/写请求时,实际的硬件I/O一般就紧接着发生了,块设备则不然,它利用一块系统内存作缓冲区,当用户进程对设备请求能满足用户的要求,就返回请求的数据,如果不能,就调用请求函数来进行实际的I/O操作。块设备是主要针对磁盘等慢速设备设计的,以免耗费过多的CPU时间来等待。
已经提到,用户进程是通过设备文件来与实际的硬件打交道。每个文件都有两个设备号,第一个是主设备号,标识驱动程序,第二个是从设备号,标识使用同一个设备驱动程序的不同的硬件设备,比如有两个软盘,就可以用从设备号来区分他们。设备文件的的主设备号必须与设备驱动程序在登记时申请的主设备号一致,否则用户进程将无法访问到驱动程序。
二 主设备和次设备号
设备号是在驱动module中分配并注册的,也就是说,驱动module拥有这个设备号,而/dev目录下的设备文件是根据这个设备号创建的,因此,当访问/dev目录下的设备文件时,驱动module就知道,自己该出场服务了(当然是由内核通知)。
在Linux内核看来,主设备号标识设备对应的驱动程序,告诉Linux内核使用哪一个驱动程序为该设备(也就是/dev下的设备文件)服务;而次设备号则用来标识具体且唯一的某个设备。
下面是我的系统/dev目录下的磁盘设备文件
第5列的8是主设备号,与磁盘驱动程序对应;第6列的0、1、2、5是次设备号,与磁盘的各个分区对应。
设备号的表示
在内核中,dev_t类型用来保存设备的设备号,包括主设备号和次设备号。要想获得设备的主设备或者次设备号,可以采用下面的两个函数:
MAJOR(dev_t dev)
MINOR(dev_t dev)
相反,如果需要将主设备号或者次设备号转换成dev_t类型,则使用:
MKDEV(int major,int minor)
设备的分配与释放
在建立一个硬件设备之前,驱动程序必须获得一个或者多个设备的设备编号。
如果事先已经知道了要使用的设备号,可以采用register_chrdev_region函数进行注册,该函数的说明如下:
/**
188 * register_chrdev_region() - register a range of device numbers
189 * @from: the first in the desired range of device numbers; must include
190 * the major number.
191 * @count: the number of consecutive device numbers required
192 * @name: the name of the device or driver.
193 *
194 * Return value is zero on success, a negative error code on failure.
195 */
196int register_chrdev_region(dev_t from, unsigned count, const char *name);
大多数情况下,我们并不知道我们将要使用哪些主设备号,这是可以采用alloc_chrdev_region函数动态分配并完成注册。
/**
222 * alloc_chrdev_region() - register a range of char device numbers
223 * @dev: output parameter for first assigned number
224 * @baseminor: first of the requested range of minor numbers
225 * @count: the number of minor numbers required
226 * @name: the name of the associated device or driver
227 *
228 * Allocates a range of char device numbers. The major number will be
229 * chosen dynamically, and returned (along with the first minor number)
230 * in @dev. Returns zero or a negative error code.
231 */
232int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
233 const char *name)
不论采用哪种方法分配设备编号,驱动程序都应该在不再使用它们的时候要释放这些设备编号,设备编号的释放主要采用下面的函数:
/**
299 * unregister_chrdev_region() - return a range of device numbers
300 * @from: the first in the range of numbers to unregister
301 * @count: the number of device numbers to unregister
302 *
303 * This function will unregister a range of @count device numbers,
304 * starting with @from. The caller should normally be the one who
305 * allocated those numbers in the first place...
306 */
307void unregister_chrdev_region(dev_t from, unsigned count)