1 / 61

第 10 章 设备管理

第 10 章 设备管理. 第 10 章 主要内容. 本章主要介绍了设备管理方面的有关知识: ◆ 系统管理设备的方式。 ◆ 驱动程序运作过程。 ◆ 驱动程序的具体实例。. 第 10 章 目录. 10.1 设备管理结构 10.2 驱动程序 10.3 驱动程序编写实例. 第 10 章 目录. 10.1 设备管理结构 10.2 驱动程序 10.3 驱动程序编写实例. 10.1 设备管理结构:. 概述.

tobias
Download Presentation

第 10 章 设备管理

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第10章 设备管理

  2. 第10章 主要内容 本章主要介绍了设备管理方面的有关知识: ◆ 系统管理设备的方式。 ◆ 驱动程序运作过程。 ◆ 驱动程序的具体实例。

  3. 第10章 目录 10.1设备管理结构 10.2 驱动程序 10.3 驱动程序编写实例

  4. 第10章 目录 10.1设备管理结构 10.2 驱动程序 10.3 驱动程序编写实例

  5. 10.1 设备管理结构: 概述 设备管理即输入输出子系统,分为上下两部分: 1. 上层的,与设备无关的,这部分根据输入输出请求,通过特定的设备驱动程序接口,来与设备进行通信。 2. 下层的,与设备有关的,常称为设备驱动程序,它直接与相应设备打交道,并且向上层提供一组访问接口。

  6. 10.1 设备管理结构:概述 设备管理的目标是对所有的外接设备进行良好的读、写、控制等操作。 待解决问题: 怎样将任意的一个设备的所有操作进行归纳,设计出统一的接口。 内核常常使用设备类型、主设备号和次设备号来标识一个具体的设备。

  7. 10.1 设备管理结构:概述 Linux中的设备管理应用了设备文件这个概念来统一设备的访问接口。 简单的说,系统试图使它对所有各类设备的输入、输出看起来就好像对普通文件的输入、输出一样。

  8. 如图10-1所示,应用程序通过Linux的系统调用与内核通信。

  9. 10.1 设备管理结构:概述 由于Linux中将设备当作文件来处理,所以对设备进行操作的系统调用和对文件操作的类似,主要包括open()、read()、write()、ioctl()、close()等。 应用程序发出系统调用指令以后,会从用户态转换到内核态,通过内核将open()这样的系统调用转换成对物理设备的操作。

  10. 10.1 设备管理结构: 字符设备与块设备 字符设备以字节为单位进行数据处理。字符设备通常只允许按顺序访问,一般不使用缓存技术。如鼠标,声卡等。 块设备以块为单位进行处理,块的大小通常为0.5KB到32KB等。

  11. 10.1 设备管理结构:字符设备与块设备 • 大多数块设备允许随机访问,而且常常采用缓存技术。 • 块设备有硬盘、光盘驱动器等。可以查看文件/proc/devices获得。 • 这里主要讨论字符设备,有兴趣的读者可参考其它书籍中有关块设备的内容。

  12. 10.1 设备管理结构: 主设备号和次设备号 设备管理中,除了设备类型(字符设备或块设备)以外,内核还需要一对称做主、次设备号的参数,才能唯一表示设备。

  13. 10.1 设备管理结构:主设备号和次设备号 主设备号(major number)相同的设备使用相同的驱动程序,而次设备号 (minor number) 用来区分具体设备的实例。 例如:第一IDE接口上的所有磁盘及其分区共用同一主设备号3,而次设备号则为0,1,2,3 …。

  14. 10.1 设备管理结构: Linux设备命名习惯 Linux习惯上将设备文件放在目录/dev或其子目录之下。 设备文件命名(通常由两部分组成)规则为: 第一部分通常较短,可能只有2或3个字母组成,用来表示设备大类。 例如:普通硬盘如IDE接口的为“hd”,软盘为“fd”。

  15. 10.1 设备管理结构: Linux设备命名习惯 第二部分通常为数字或字母用来区别设备实例。 例如: /dev/hda、/dev/hdb、/dev/hdc表示第一、二、三块硬盘;而 dev/hda1、/dev/hda2、/dev/hda3则表示第一硬盘的第一、二、三分区。

  16. 第10章 目录 10.1设备管理结构 10.2 驱动程序 10.3 驱动程序编写实例

  17. 10.2 驱动程序: 驱动程序基本功能 在Linux操作系统中驱动程序是操作系统内核与硬件设备之间的桥梁,它屏蔽了硬件的细节 (如总线协议、DMA操作等),在应用程序看来硬件设备只是一个特殊的文件。

  18. 10.2 驱动程序:驱动程序基本功能 驱动程序的基本功能为: 1. 对设备初始化和释放。如对音频设备而言包括向内核注册设备,设置音频的输入输出参数 (如采样频率、采样宽度等)、分配音频设备使用的内核内存等工作。 2. 对设备进行管理。包括实时参数设置以及提供对设备的操作接口。

  19. 10.2 驱动程序:驱动程序基本功能 3. 读取应用程序传送给设备文件的数据并回送应用程序请求的数据。这需要在用户空间、内核空间、总线及外设之间传输数据。 4. 检测和处理设备出现的错误。

  20. 10.2 驱动程序:驱动程序的运作过程 当一个程序读/dev/tty文件(此为键盘)时,就会执行系统调用sys_read()(在fs/read_write.c中),该系统调用在判别出所读文件是一个字符设备文件时,即会调用rw_char()函数(在fs/char_dev.c中),该函数则会根据所读设备的设备类型,主、次设备号等参数,由字符设备读写函数表(设备开关表)调用rw_tty(),最终调用到这里的终端读操作函数tty_read()

  21. 10.2 驱动程序:驱动程序的运作过程 当用户在键盘上键入了一个字符时,会引起键盘中断响应,此时键盘中断处理程序就会从键盘控制器读入对应的键盘扫描码,然后根据使用的键盘扫描码映射表译成相应字符,放入tty读队列read_q中。

  22. 10.2 驱动程序:驱动程序的运作过程 然后调用中断处理程序的do_tty_interrupt()函数,它又直接调用行规则函数copy_to_cooked()对该字符进行过滤处理,并放入tty辅助队列secondary中,供上述tty_read()读取。

  23. 10.2 驱动程序:驱动程序的运作过程 同时把该字符放入tty写队列write_q中,并调用写控制台函数con_write()。 此时如果该终端的回显(echo)属性是设置的,则该字符会显示到屏幕上(注:do_tty_interrupt()和copy_to_cooked()函数在tty_io.c中实现)。

  24. 10.2 驱动程序: 常用接口介绍 open(): 打开设备,并初始化设备准备进行操作。可以为NULL,这样每次打开设备总会成功,而且不通知设备驱动程序。 read(): 从设备中读数据,需要提供字符串指针。 write(): 向字符设备写数据,需要提供所写内容指针。 ioctl(): 控制设备,例如控制光盘的弹出等。需要提供符合设备预先定义的命令字。

  25. 10.2 驱动程序:常用接口介绍 llseek(): 重新定位读、写位置,需要提供偏移量参数。 flush(): 清除内容。 release(): 关闭设备,并释放资源等。 mmap(): 将设备内存映射到进程地址空间。通常只有块设备驱动程序使用。

  26. 10.2 驱动程序: 常用函数原型 1. 设备操作函数原形 struct file_operations { struct module * owner; loff_t(*llseek) (struct file *, loff_t,int); ssize_t(*read) (struct file *,char*,size_t,loff_t *); ssize_t(*write)(struct file *,const char *,size_t,loff_t *); int (*readdir)(struct file *,void *,filldir_t);

  27. unsigned int(*poll)(struct file *,struct poll_table_struct *); int (*ioctl)(struct inode *,struct file *,unsigned int ,unsigned long ); int (mmap)(struct file *,struct vm_area_struct *); int (*open)(struct inode *,struct file *); int (*flush)(struct file*); int(*release)(struct inode *,struct file *);

  28. 10.2 驱动程序:常用函数原型 int (*fsync )(struct file ,struct dentry *,int datasync); int (*fasync )(int,struct file *,int); int (*lock)(struct file *,int struct file_lock *); ssize_t(*readv)(struct file *,const struct iovec *,unsigned long,loff_t *); ssize_t(*writev)(struct file *,const struct iovec *,unsigned long,loff_t *); }

  29. 10.2 驱动程序:常用函数原型 2.向系统注册的函数原形 int register_chrdev(unsigned int major,const char * name,struct file_operations * fops) { if (major = = 0 ) { write_lock(&chrdevs_lock);

  30. 10.2 驱动程序:常用函数原型 for(major=MAX_CHRDEV-1;major>0;major--) { if (chrdevs[major].fops= =NULL) { chrdevs[major].name=name; chrdevs[major].fops=fops; write_unlock(&chrdevs_lock); return major; } }

  31. 10.2 驱动程序:常用函数原型 write_unlock(&chrdevs_lock); return -EBUSY; } if(major>MAX_CHRDEV) return -EINVAL; write_lock(&chrdevs_lock);

  32. if(chrdevs[major].fops && chrdevs[major].fops!=fops) { write_unlock(&chrdevs_lock); return -EBUSY; } chrdevs[major].name=name; chrdevs[major].fops=fops; write_unlock(&chrdevs_lock); return 0; } 10.2 驱动程序:常用函数原型

  33. 第10章 目录 10.1设备管理结构 10.2 驱动程序 10.3 驱动程序编写实例

  34. 10.3 驱动程序编写实例 为了更清楚地讲述Linux中设备驱动程序的编写,加深读者对启动程序的了解。下面介绍一个简单的设备驱动的实现过程。 由于基于特殊的硬件设备实现的驱动程序难度较大,而且不方便验证,下面举一个虚拟设备驱动程序的例子。

  35. 10.3 驱动程序编写实例: 设备功能介绍 实现虚拟设备的写入、读出等操作。这个驱动程序并不是基于特定硬件设备的,实际上仅仅是对内存进行读、写操作。

  36. 10.3 驱动程序编写实例:设备功能介绍 1. 函数mydrv_read()的功能是从mybuf[100]中读取字符串,并传递给调用的进程。 2. 函数mydrv_write()的功能是将调用的进程传入的字符串赋值给mybuf,如果字符串的长度超过100,则只取前100个字符。 3. 函数mydrv_ioctl()中仅仅实现了一个控制功能:清除mybuf存储区。

  37. 10.3 驱动程序编写实例: 具体实现 首先,要根据设备功能的需要,编写file_operations结构中的操作函数。 其次,要向系统注册该设备,包括字符设备的注册,devfs节点的注册与中断响应函数的注册。然后就可以利用对应的文件进行设备操控了。具体如下:

  38. 1.源程序: 10.3 驱动程序编写实例:具体实现 # include <linux/module.h> # include <linux/kernel.h> # include <linux/fs.h> # include <linux/types.h> # include <linux/malloc.h> # include <asm/uaccess.h> # include <asm/page.h> # include <linux/ermo.h> # include <linux/config.h>

  39. 10.3 驱动程序编写实例:具体实现 # define MYDRV_CLS_IO( 'c' ,0x01 ) //定义清存储区命令字 char mybuf[100]; //存储区域 int mydrv_major = 99; //主设备号 devfs_handle_t dev_handle; //保存设备文件系统的注册句柄 //第一步:编写file_operations函数

  40. 10.3 驱动程序编写实例:具体实现 ssize_t mydrv_read(struct file * filp, char * buf, size_t count,loff_t * f_pos); //函数声明 static ssize_t mydrv_write(struct file * filp,const char * buf,size_t count,loff_t * ppos); static int mydrv_ioctl( struct inode * inode,struct file * file, unsigned int cmd, unsigned long arg); int mydrv_open (struct inode * inode,struct file *filp); int mydrv_release(struct inode * inode, struct file * filp); //函数声明

  41. struct file_operations mydrv_ops={ //设备函数接口 open: mydrv_open , //实现对设备的操作 read: mydrv_read, write: mydrv_write, ioctl: mydrv_ioctl, release: mydrv_release; }; // mydrv_read()将内核空间的mybuf中的字符串赋给用户空间的buf区 10.3 驱动程序编写实例:具体实现

  42. 10.3 驱动程序编写实例:具体实现 ssize_t mydrv_read(struct file * filp, char * bur, size_t count,loff_t * f_pos) //filp:指向设备文件的指针;f_pos:偏移量 int length = strlen(mybuf); if(count > 99) count = 99; //忽略大于100部分 count = length - * f_pos; //计算字符个数的技巧

  43. if(copy_to_user(buf, mybuf, count) ) { //重内核区复制到用户区 printk("error reading, copy_to_user\n”); retum -EFAULT; } *f_pos += count; //下一个 retum count; } // mydtv_write()将用户空间的buf字符串赋给内核空间的mybuf [ ]数组中 10.3 驱动程序编写实例:具体实现

  44. static ssize_t mydrv_write(struct file * filp,const char * buf, size_t count,loff_t * ppos){ int num; num=count<100? count: 100; if(copy_from_user(mybuf, buf, num)) //mybufbuf return -EFAULT; printk("mydrv_write succeed! \ n”); return num; } 10.3 驱动程序编写实例:具体实现

  45. static int mydrv_ioctl( struct inode * inode,struct file * file, //如果传人的命令字是 unsigned int cmd, unsigned long arg){ //MYDRV-CLS则清除mybuf数组内容 switch ( cmd ){ case MYDRV_CLS: mybuf[0] = 0x0; return 0; default: return -EINVAL; } } //打开mydrv设备时调用 10.3 驱动程序编写实例:具体实现

  46. 10.3 驱动程序编写实例:具体实现 # define MAX_MYDRV_DEV 2 int mydrv_open (struct inode * inode,struct file *filp){ //inede:设备文件节点 unsigned int dev = MINOR(inode- >i_rdev); if(mydrv_num) return -1;

  47. if (dev > = MAX_MYDRV_DEV) return -ENODEV; filp- > f_ap = &mydrv_ops; //指向操作函数 printk(“open success\n”); MOD_INC_USE_COUNT; //只是简单地加1 return 0; } //关闭mydrv设备,这里只是将引用次数减1 int mydrv_release(struct inode * inode, struct file * filp){ MOD_DEC_USE_COUNT; return 0; } 10.3 驱动程序编写实例:具体实现

  48. 10.3 驱动程序编写实例:具体实现 //第二步:向系统注册该设备 // module的安装,采用两种方式进行了设备的注册 int init_module(void) { int result; printk(“initing...\ n”); result = devfs_register_chrdev(mydrv_major, “mydrv”,&mydrv_ops);

  49. if (result < 0){ printk(KERN_WARNING “mydrv: unable to get major %d \ n”, mydrv_major); return result; } dev_handle = devfs_register( NULL, “mydrv", DEVFS_FL_DEFAULT, 99,0, S_IFCHR, &mydrv_ops, NULL); //devfs_register(devfs_handle_t dir,const char *name,unsigned int flags, //unsigned int major,unsigned int minor,umode_t mode,void *ops,void *info) 10.3 驱动程序编写实例:具体实现

  50. if (mydrv_major:= = 0) mydrv_major = result; strcpy(mybuf,"Hello, please write anything ( length <100)to mydrv.”); printk(“succeed in getting buffer \ n"); printk("%s \ n", mybuf); retum 0; } // module的卸载,进行设备的注销 10.3 驱动程序编写实例:具体实现

More Related