Linux字符设备基础.doc_第1页
Linux字符设备基础.doc_第2页
Linux字符设备基础.doc_第3页
Linux字符设备基础.doc_第4页
Linux字符设备基础.doc_第5页
免费预览已结束,剩余2页可下载查看

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Linux字符设备基础字符设备驱动程序在系统中的位置操作系统内核需要访问两类主要设备,简单的字符设备,如打印机,键盘等;块设备,如软盘、硬盘等。与此对应,有两类设备驱动程序。分别称为字符设备驱动程序和块设备驱动程序。两者的主要差异是:与字符设备有关的系统调用几乎直接和驱动程序的内部功能结合在一起。而读写块设备则主要和快速缓冲存储区打交道。只有需要完成实际的输入输出时,才用到块设备驱动程序。见下图:用户程序系统调用接口文件系统高速缓存字符设备块设备驱动程序硬设备Linux设备驱动程序的主要功能有:l 对设备进行初始化;l 使设备投入运行和退出服务;l 从设备接收数据并将它们送到内核;l 将数据从内核送到设备;l 检测和处理设备出现的错误。当引导系统时,内核调用每一个驱动程序的初始化函数。它的任务之一是将这一设备驱动程序使用的主设备号通知内核。同时,初始化函数还将驱动程序中的函数地址结构的指针送给内核。内核中有两张表。一张表用于字符设备驱动程序,另一张用于块设备驱动程序。这两张表用来保存指向file_operations结构的指针,设备驱动程序内部的函数地址就保存在这一结构中。内核用主设备号作为索引访问file_operations结构,因而能访问驱动程序内的子程序。从开机到驱动程序的载入系统启动过程中可能出现几种不同的方式检测设备硬件。首先机器硬件启动时BIOS会检测一部分必要的设备,如内存、显示器、键盘和硬盘等等。机器会把检测到的信息存放在特定的位置,如CMOS数据区。而另外某些设备会由设备驱动程序进行检测。1 开机2 引导部分(linux/config.h,arch/i386/boot/bootsect.S)3 实模式下的系统初始化(arch/i386/boot/setup.S) 4 保护模式下的核心初始化5 启动核心(init/main.c)init函数中函数调用关系如下:main.c init()filesystems.csys_setup() genhd.cdevice_setup()mem.cchr_dev_init()至此,驱动程序驻入内存。设备驱动程序基本数据结构:struct device_struct系统启动过程中要登记的块设备和字符设备管理表的定义在文件fs/devices.c中:struct device_struct const char * name;struct file_operations * fops;static struct device_struct chrdevsMAX_CHRDEV;static struct device_struct blkdevsMAX_BLKDEV;其实块设备表和字符设备表使用了相同的数据结构。在某些系统中,这些设备表也称作设备开关表,不同的是它们直接定义了一组函数指针进行对设备的管理。而这里系统用文件操作(file_operations)代替了那组开关。文件操作是文件系统与设备驱动程序之间的接口,系统特殊文件在建立的时候并没有把两者对应起来,只是把设备的缺省文件结构和i节点结构赋给设备文件,而真正的对应定义在系统启动之后,当设备被打开时时才进行的。操作blkdev_open和chrdev_open定义在文件devices.c中,它们的基本功能是当设备文件初次打开时,根据该文件的i节点信息找到设备真正的文件操作接口,然后更新原来的设备表项;最后再调用该设备的open操作。/include/linux/major.h中定义了设备表的长度。设备表中不同的表项表示不同种类的设备,也就是说,LINUX系统分别支持各128种不同的块设备和字符设备。Struct file_operations操作系统将一个字符设备当作文件来处理,内核通过file_operations结构来访问driver的功能。这也是linux的OO思想的体现之一。file_operations的定义在文件中。每个字符设备都有一个file_operatioins结构。这个结构指向一组操作函数(open,read).每个函数的定义由driver提供。当然,有些标准操作某些设备并不支持,这时,file_operatons结构中对应表项为NULL(.随着linux内核的不断升级,file_operatioins结构也不断变大。最新的版本中,甚至函数原型也发生了一些变化。当然,新版本总会向下兼容的。)下面是2.0.35中的file_operations结构定义:struct file_operations int (*lseek) (struct inode *, struct file *, off_t, int); int (*read) (struct inode *, struct file *, char *, int); int (*write) (struct inode *, struct file *, const char *, int); int (*readdir) (struct inode *, struct file *, void *, filldir_t); int (*select) (struct inode *, struct file *, int, select_table *); int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); int (*mmap) (struct inode *, struct file *, struct vm_area_struct *); int (*open) (struct inode *, struct file *);void (*release) (struct inode *, struct file *); int (*fsync) (struct inode *, struct file *); int (*fasync) (struct inode *, struct file *, int); int (*check_media_change) (kdev_t dev); int (*revalidate) (kdev_t dev);Struct inodefile_operations中的大多数操作都将inode做为第一个参数。Linux的VFS是对物理文件系统,物理设备的一个封装。Inode结构就是VFS与下层模块对话的重要结构。文件系统由子目录和文件构成。每个子目录或文件只能由唯一的inode描述。每个设备也是用inode来描述的。inode 是LINUX管理文件系统的最基本单位,也是文件系统连接任何子目录、任何文件,设备的桥梁。struct inode kdev_ti_dev;/* 文件所在设备的设备号,第一个IDE硬盘为0x0301 */unsigned longi_ino;/* 外存inode的节点号, (i_dev,i_ino)在VFS中是唯一的 */umode_ti_mode;/* 表示文件类型以及存取权限 */nlink_ti_nlink;/* 连接到该文件的link数 */uid_ti_uid;/* 用户标识号 */gid_ti_gid;/* 用户组标识号 */kdev_ti_rdev;/* 根设备的设备号 */off_ti_size;/* 文件长度 */time_ti_atime;/* 文件访问时间 */time_ti_mtime; /* 文件修改时间 */time_ti_ctime; /* 文件创建时间 */unsigned longi_blksize;/* 以字节为单位的块大小,一般为1024字节 */unsigned longi_blocks; /* 文件块数 */unsigned longi_version;unsigned longi_nrpages;/* 文件在内存中所占页数 */struct semaphore i_sem; /* 信号量 */struct inode_operations *i_op; /* 指向一组针对该文件的操作函数,见fs.h */struct super_block *i_sb;/* 指向内存中VFS的超级块 */struct wait_queue *i_wait; /* 在该文件上的等待队列 */struct file_lock *i_flock;struct vm_area_struct *i_mmap;struct page *i_pages; /* 由文件占用页面构成的单向链,通过它可访问内存中的文件数据 */struct dquot *i_dquotMAXQUOTAS;struct inode *i_next, *i_prev; /* inode资源管理中使用的链表指针 */struct inode *i_hash_next, *i_hash_prev; /* inode cache的链表指针 */struct inode *i_bound_to, *i_bound_by;struct inode *i_mount;/* 指向下挂文件系统的inode的根目录 */unsigned long i_count;/* 引用记数,0表示是空闲inode */unsigned short i_flags;unsigned short i_writecount;unsigned char i_lock; /* 对inode加锁标志 */unsigned char i_dirt;unsigned char i_pipe;unsigned char i_sock;unsigned char i_seek;unsigned char i_update; unsigned char i_condemned;union /* 各类文件系统inode的特定信息 */ .struct ext2_inode_info ext2_i; . u;对于设备管理而言,主要用到的是inode结构的 kdev I_rdev字段。Struct kdev_t文件系统中,字符设备是通过名字来访问的。通常字符设备都在/dev下。在系统内部,每个字符设备都用设备号来表示。设备号由主,副设备号来表示。主设备号表示与设备对应的设备驱动程序。如:设备/dev/zero 和 /dev/null都用1作为主设备号,表示他们使用相同的设备驱动程序。副设备号只供驱动程序使用。通常一个驱动程序控制几个设备,它通过副设备号来辨别他们。与设备号相关的数据结构为kdev_tKdev_t 结构主要用来表示一个设备的主设备号和副设备号。它其实只是一个短的非负整数:typedef unsigned short kdev_t;但是,我们可以把它看作:typedef struct unsigned short major, minor; kdev_t;内核提供了一组宏来操作kdev_t结构:MAJOR(kdev_t dev) : extract the major number from a kdev_t structureMINOR(kdev_t dev) : extract the minor number from a kdev_t structureMKDEV( int ma, int mi):return a kdev_t built from major and minor numbers旧版本的内核dev_t对应kdev_t Struct file中定义的file 结构是设备驱动程序中用到的仅次于file_operations的数据结构。这里的file结构和用户程序用到的FILE结构不同。它们定义在不同的空间。一个file结构代表一个”打开的文件”,它在文件被打开时被创建,然后被传给要对文件进行操作的函数,知道文件被关闭。一个打开的文件和一个磁盘上的文件不同,磁盘文件用inode表示。下面讨论一些重要的域:mode_t f_mode;文件的读写模式由f_mode的FMODE_READ和FMODE_WRITE控制。在ioctl函数中需要通过此位控制文件的读写权限。当然,read ,write函数不需要检查f_mode因为读写权限的检查是由内核在调用他们之前进行的。loff_t f_pos当前的读写位置。Loff_t是一个64位的值。unsigned short f_flags;也是文件的一些标志。如:O_RDONLY,O_NONBLOCK和O_SYNC.驱动程序必须检查f_flags以进行非阻塞操作。读写操作控制必须用f_mode.struct inode * f_inode;所打开的文件对应的inode,struct file_operations * f_op;对打开的文件的处理函数。一般在打开文件或设备初始化时由内核赋值。可以动态的修改此结构来改变文件的处理函数。void *private_data;open 系统调用把此指针设为NULL,然后再调用驱动程序的open函数。驱动程序可以自由得使用,甚至忽略它。struct file mode_t f_mode;loff_t f_pos;unsigned short f_flags;unsigned short f_count;unsigned long f_reada, f_ramax, f_raend, f_ralen, f_rawin;struct file *f_next, *f_prev;struct fown_struct f_owner;struct inode * f_inode;struct file_operations * f_op;unsigned long f_version;void *private_data;/* needed for tty driver, and maybe others */;驱动程序的安装写完了设备驱动程序,下一项任务是对它进行编译和装入可引导的内核。实际上这并不复杂,可以用下面的步骤来完成:l 将drivers.c和任何有关的drivers.h文件复制包含字符设备驱动程序源码的目录下,它放在Linux源程序目录下的drivers/char子目录中。l 在chr_dev_init()函数的最后增加调用init()子程序的行。chr_dev_init()函数在drivers/char/mem.c中。l 编辑drivers/char目录中的makefile,将drivers.o的名称放在OBJS定义的后面,并将drivers.c名称放在SRCS定义的后面。l 将重启动函数加到main.c中的bootsetups数组l 重新编译和安装新的内核。另:登记一个字符设备驱动程序: int register_chrdev(unsigned int major , const char * name,struct file_operations * fops);登记一个字符设备:mknod /dev/scull0 c 127 0接口函数概述所有接口函数出现于file_operation中,除非专门注明,它们返回0表示成功,负值表示出错。 int (* lseek) (struct inode * , struct file *,off_t, int);lseek函数用于改变当前的读写位置,函数返回新的位置 int (* read) (struct inode * , struct file *,char * , int);读取数据。若参数指针为空,返回-EINVAL(Invalid argument)。一般返回一个非负整数表示读取的字节数。 int (* write) (struct i

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论