Linux Kernel学习笔记

转自:http://blog.sina.com.cn/s/blog_55465b470100eb8c.html

 

这里贴部分内容:

Chapter 2. 设备驱动程序开发

在编程思路上,机制表示需要提供什么功能,策略表示如何使用这些功能。区分机制和策略是UNIX设计最重要和最好的思想之一。如X系统就由X服务器和X客户端组成。X服务器实现机制,负责操作硬件,给用户程序提供一个统一的接口。而X客户端实现策略,负责如何使用X服务器提供的功能。设备驱动程序也是机制与策略分离的典型应用。在编写硬件驱动程序时,不要强加任何特定的策略。

Linux系统将设备分成三种类型,分别是字符设备、块设备和网络接口设备。

在linux中通过设备文件访问硬件,设备文件位于/dev目录下。设备文件是一种信息文件,普通文件的目的在于存储数据,设备文件的目的在于向内核提供控制硬件的设备驱动程序的信息。设备文件保存了多种信息,其中重要的有设备类型信息,主设备号(major),次设备号(minor)。主设备号与次设备号起到连接应用程序和设备驱动程序的作用。当应用程序利用open()函数打开设备文件时,内核从相应的设备文件中得到主设备号,从而查找到相应的设备驱动程序,由次设备号查找实际设备。所以主设备号对应设备驱动程序,次设备号对应由该驱动程序所驱动的实际设备。通过设备文件可以向硬件传送数据,也可从硬件接收数据。

设备文件使用mknod命令生成。mknod命令语法如下:

mknod [设备文件名] [设备文件类型] [主设备号] [次设备号]

字符设备用c表示,块设备用b表示,网络设备没有专门的设备文件。

读写设备文件时要使用低级输入输出函数,不要使用带缓冲的以f开头的流文件输入输出函数。但并不是所有低级输入输出函数都可以用在设备文件上,可以用在设备文件的低级输入输出函数有以下几个:

open() 打开文件或设备 close() 关闭文件 read() 读取数据 write() 写数据 lseek() 改变文件的读写位置 ioctl() 实现read(),write()外的特殊控制,该函数只在设备文件中使用 fsync() 实现写入文件上的数据和实际硬件的同步

Chapter 3. 字符设备驱动程序

3.1. 设备号

字符设备在系统中以设备文件的形式表示,位于/dev目录下。每个字符设备都有一个主设备号和次设备号,主设备号标识设备对应的驱动程序,次设备号标识设备文件所指的具体设备。

主次设备号的数据类型是dev_t,在/linux/types.h中定义。在2.6内核中,dev_t是一个32位的数,其中12位用来表示主设备号,其余20位用来表示次设备号。要获得设备的主次设备号可以使用内核提供的宏:

MAJOR(dev_t dev); #获得主设备号 MINOR(dev_t dev); #获得次设备号

这些宏定义位于linux/kdev_t.h中。如果要把主次设备号转换成dev_t类型,则可使用:

MKDEV(int major, int minor);

3.2. 设备号的分配和释放

在建立一个字符设备之前,需要为它分配一个或多个设备号。使用register_chrdev_region()函数完成设备号的分配。该函数在linux/fs.h中声明。原型如下:

int register_chrdev_region(dev_t first, unsigned int count, char *name); first:是要分配的主设备号范围的起始值,次设备号一般设置为0; count:是所请求的连续设备号的个数; name:是和该设备号范围关联的设备名称,它将出现在/proc/devices或/sysfs中。

如果分配成功则返回0,分配失败则返回一个负的错误码,所请求的设备号无效。

还有一个自动分配设备号的函数alloc_chrdev_region(),原型如下:

int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name); dev: 自动分配到设备号范围中的第一个主设备号; firstminor:自动分配的第一个次设备号,通常为0; count: 是所请求的连续设备号的个数; name: 是和该设备号范围关联的设备名称,它将出现在/proc/devices或/sysfs中。

如果我们不再使用设备号,则要使用unregister_chrdev_region()函数释放它。函数原型如下:

void unregister_chrdev_region(dev_t first, unsigned int count); 函数的参数作用同上

我们一般在模块的清除函数中调用设备号释放函数。

在内核源码目录的Documentation/devices.txt文件中列出了已静态分配给常用设备的主设备号。为了减少设备号分配的冲突,我们一般要使用alloc_chrdev_region()函数来自动分配设备号。

3.3. 重要的数据结构

文件操作结构:struct file_operations,在linux/fs.h中定义。它包含一组函数指针,实现文件操作的系统调用,如read、write等。每个打开的文件都和一个文件操作结构关联(通过file结构中指向file_operations结构的f_op字段进行关联)。

文件结构:struct file,在linux/fs.h中定义。file结构代表一个打开的文件,由内核在open时创建。指向文件结构的指针在内核中通常称为filp(文件指针)。当文件的所有实例都被关闭之后,内核会释放这个数据结构。

节点结构:struct inode,在linux/fs.h中定义。inode结构是内核表示文件的方法,而file结构是以文件描述符的方式表示文件的方法。结构中以下两个字段对编写驱动程序有用:

  • dev_t i_rdev,该字段包含了真正的设备编号。

  • struct cdev *i_cdev,该字段包含指向struct cdev结构的指针。

从设备的inode获取主次设备号的宏:

unsigned int iminor(struct inode *inode); unsigned int imajor(struct inode *inode);

3.4. 读和写

下面两个是字符设备读写操作最重要的内核函数。

unsigned long copy_to_user (void __user * to, const void * from, unsigned long n); 读操作,把数据从内核空间复制到用户空间,返回不能复制的字节数,如果成功则返回0。 to 目的地址,在用户空间中; from 源地址,在用户空间; n 要复制的字节数。 unsigned long copy_from_user (void * to, const void __user * from, unsigned long n); 写操作,把数据从用户空间复制到内核空间,返回不能复制的字节数,如果成功则返回0。 to 目的地址,在内核空间中; from 源地址,在用户空间; n 要复制的字节数。

Linux Kernel学习笔记,古老的榕树,5-wow.com

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。