第10章 设备管理.

Slides:



Advertisements
Similar presentations
面向侧面的程序设计 方林博士 本文下载地址:
Advertisements

LSF系统介绍 张焕杰 中国科学技术大学网络信息中心
第一章 C语言概述 计算机公共教学部.
基于ARM和linux的开发 华中科技大学 武汉创维特 2017/3/20.
C++中的声音处理 在传统Turbo C环境中,如果想用C语言控制电脑发声,可以用Sound函数。在VC6.6环境中如果想控制电脑发声则采用Beep函数。原型为: Beep(频率,持续时间) , 单位毫秒 暂停程序执行使用Sleep函数 Sleep(持续时间), 单位毫秒 引用这两个函数时,必须包含头文件
在PHP和MYSQL中实现完美的中文显示
计算机基础知识 丁家营镇九年制学校 徐中先.
Linux Further.
嵌入式操作系统 陈香兰 Fall 2009.
Kvm异步缺页中断 浙江大学计算机体系结构实验室 徐浩.
LSF系统介绍 张焕杰 中国科学技术大学网络信息中心
複習 struct score_Type{ int chinese,english; }; struct my_Type{
Hadoop I/O By ShiChaojie.
计算概论 第二十一讲 文件操作 北京大学信息学院.
补充内容 结构体 概述 定义结构体类型和定义结构体变量 结构体变量的引用 结构体变量的初始化 指针与结构体 用typedef定义类型的别名.
第十一章 文件 文件概述 文件操作 文件操作实例 本章小结 作业: 练习:
11.1 文件的基本概念 11.2 文件的打开与关闭 11.3 文件的顺序读写 11.4 文件的随机读写 11.5 文件检测
走进编程 程序的顺序结构(二).
辅导课程六.
SPI驱动 广州创龙电子科技有限公司 Guangzhou Tronlong Electronic Technology Co., Ltd.
Zhao4zhong1 (赵中) C语言指针与汇编语言地址.
Zhao4zhong1 (赵中) C语言指针与汇编语言地址.
第十二章 文件 12.1 C文件概述 文件:存储在外部介质上数据的集合,是操作系统数据管理的单位 文件分类 按文件的逻辑结构: 按存储介质:
第一单元 初识C程序与C程序开发平台搭建 ---观其大略
fp=fopen("CD2.dat","wb"); fwrite(&min,8,1,fp); fclose(fp);
文件读写实践 广州创龙电子科技有限公司 01 广州创龙电子科技有限公司
按键驱动 广州创龙电子科技有限公司 Guangzhou Tronlong Electronic Technology Co., Ltd.
THE C PROGRAMMING LANGUAGE
如何生成设备节点 广州创龙电子科技有限公司
Linux 文件操作——系统调用和标准 IO 库
第9章 文件操作 文件 使用文件的目的 操作系统管理数据的基本单位 存储在外存储器上的数据的集合
Windows 7 的系统设置.
用event class 从input的root文件中,由DmpDataBuffer::ReadObject读取数据的问题
宁波市高校慕课联盟课程 与 进行交互 Linux 系统管理.
Java语言程序设计 清华大学出版社 第8章 输入输出流(1).
宁波市高校慕课联盟课程 与 进行交互 Linux 系统管理.
第1章 概述 本章要点: C语言程序结构和特点 C语言程序的基本符号与关键字 C语言程序的编辑及运行 学习方法建议:
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
第二章 登录UNIX操作系统.
内容摘要 ■ 课程概述 ■ 教学安排 ■ 什么是操作系统? ■ 为什么学习操作系统? ■ 如何学习操作系统? ■ 操作系统实例
一、文件的基本概念 第十三章 文 件 所谓“文件”是指一组相关数据的有序集合。 这个数据集有一
C语言程序设计 主讲教师:陆幼利.
微机系统的组成.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
本节内容 随机读取 视频提供:昆山爱达人信息技术有限公司.
实验七 安全FTP服务器实验 2019/4/28.
本节内容 Win32 API中的宽字符 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
第4章 Excel电子表格制作软件 4.4 函数(一).
<编程达人入门课程> 本节内容 为什么要使用变量? 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ:
iSIGHT 基本培训 使用 Excel的栅栏问题
第二章 类型、对象、运算符和表达式.
本节内容 结构体 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
C++语言程序设计 C++语言程序设计 第二章 基本数据类型与表达式 第十一组 C++语言程序设计.
LOGIX500软件入门 西安华光信息技术有限公司 2008年7月11日.
本节内容 文件系统 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
多层循环 Private Sub Command1_Click() Dim i As Integer, j As Integer
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
本节内容 C语言的汇编表示 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
第13章 文 件.
_08文件操作 本节课讲师——void* 视频提供:昆山爱达人信息技术有限公司 官网地址:
基于列存储的RDF数据管理 朱敏
C++语言程序设计 C++语言程序设计 第一章 C++语言概述 第十一组 C++语言程序设计.
本节内容 动态链接库 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
本节内容 进程 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
第四章 UNIX文件系统.
FVX1100介绍 法视特(上海)图像科技有限公司 施 俊.
设备管理与模块机制 基本概念 传统方式的设备注册与管理 devfs注册与管理 块设备的请求队列 网络设备 模块机制
使用Fragment 本讲大纲: 1、创建Fragment 2、在Activity中添加Fragment
Presentation transcript:

第10章 设备管理

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

结合大家比较熟悉的键盘来了解其运作过程:

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

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

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

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

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

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

10.2 驱动程序: 常用函数原型 1. 设备操作函数原形 { struct module * owner; 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);

int (mmap)(struct file *,struct vm_area_struct *); 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 *);

10.2 驱动程序:常用函数原型 int (*fasync )(int,struct file *,int); 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 *); } 10.2 驱动程序:常用函数原型

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

10.2 驱动程序:常用函数原型 { if (chrdevs[major].fops= =NULL) 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; } 10.2 驱动程序:常用函数原型

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

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

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

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

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

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

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

10.3 驱动程序编写实例:具体实现 1.源程序: # 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> 10.3 驱动程序编写实例:具体实现

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

ssize_t mydrv_read(struct file. filp, char. buf, size_t count,loff_t 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); //函数声明 10.3 驱动程序编写实例:具体实现

10.3 驱动程序编写实例:具体实现 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 驱动程序编写实例:具体实现

ssize_t mydrv_read(struct file. filp, char. bur, size_t count,loff_t 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; //计算字符个数的技巧 10.3 驱动程序编写实例:具体实现

10.3 驱动程序编写实例:具体实现 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 驱动程序编写实例:具体实现

static ssize_t mydrv_write(struct file. filp,const char 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 驱动程序编写实例:具体实现

static int mydrv_ioctl( struct inode. inode,struct file 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 驱动程序编写实例:具体实现

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; 10.3 驱动程序编写实例:具体实现

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; 10.3 驱动程序编写实例:具体实现

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

10.3 驱动程序编写实例:具体实现 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 驱动程序编写实例:具体实现

10.3 驱动程序编写实例:具体实现 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 驱动程序编写实例:具体实现

10.3 驱动程序编写实例:具体实现 void cleanup_module(void) { devfs_unregister_chrdev(mydrv_major, “mydrv”); devfs_unregister( dev_handle ); printk("exiting... \ n"); } 10.3 驱动程序编写实例:具体实现

10.3 驱动程序编写实例:具体实现 2.设备驱动程序编译和安装 采用下面的命令可以对mydrv.c进行编译: [root@Linux root]# gcc -c mydrv.c –D__KERNEL__ -DMODULE -O2 -g -Wall -o 如果没有出错的话,将会在本目录下生成一个mydrv.o文件。

10.3 驱动程序编写实例:具体实现 下面的操作必须是以root身份进行的(用命令su转换成root身份): 先执行模块的插入操作, [root@Unuxroot]#/sbin/insmod mydrv.o

10.3 驱动程序编写实例:具体实现 如果设备文件系统已经应用起来的话,此时在设备文件系统挂接的目录(通常是/dev)下,就可以找到mydrv文件节点了。如果没有应用设备文件系统,则需要手工为设备添加文件节点: [root@Linux/dev]#mknod mydrv c 99 0 此时就可以对设备进行读、写、ioctl等操作了。

10.3 驱动程序编写实例:具体实现 当不再需要对设备进行操作时,可以采用下面的命令卸载模块: [root@Linux/dev]#/sbin/rmmod mydrv

3.设备的使用 下面的小程序可以对任何文件进行先写后读的操作: #include <stdio.h> int main() { FILE * fp; char buf[l00]; printf("Please input file name: "); scanf("% s", buf);

10.3 驱动程序编写实例:具体实现 if((fp = fopen(buf, "wb")) = = NULL) { printf("Could not opened! \ n"); return -1; } else printf("File open ok! \ n"); printf("Please input( < 100): "); scanf("% s", buf); 10.3 驱动程序编写实例:具体实现

10.3 驱动程序编写实例:具体实现 if(fputs(buf,fp) = = EOF){ printf("Error writing file ! "); return -2; } fgets(but, 100,fp); //由文件读取一字符串 printf("the File content is: %s \ n",buf); fclose(fp); return 0; 10.3 驱动程序编写实例:具体实现

当然,也可以采用cat命令得到mydrv设备的输出内容。 10.3 驱动程序编写实例:具体实现 直接用gcc编译生成可执行文件之后,就可以用该程序对mydrv设备的文件节点进行操作。 当然,也可以采用cat命令得到mydrv设备的输出内容。

小结 本章主要介绍了设备管理方面的有关知识. 首先介绍了系统是怎样来管理设备的,即把设备看作一种的特殊的文件,从而实现了对设备的有关操作。 然后,说明了驱动程序运作过程。 最后,结合一个具体实例,阐明了驱动程序的具体的编写方法。

练习题 1.操作系统是怎么实现对设备进行管理的? 2.举出5个驱动程序的常用接口函数。 3.编写驱动程序一般有几个步骤,具体各是什么?