字符设备驱动程序的扩展操作
设备驱动程序
驱动程序驱动程序一般指的是设备驱动程序(Device Driver),是一种可以使计算机和设备通信的特殊程序。
相当于硬件的接口,操作系统只有通过这个接口,才能控制硬件设备的工作,假如某设备的驱动程序未能正确安装,便不能正常工作。
因此,驱动程序被比作“硬件的灵魂”、“硬件的主宰”、和“硬件和系统之间的桥梁”等。
中文名驱动程序外文名Device Driver全称设备驱动程序性质可使计算机和设备通信的特殊程序目录1定义2作用3界定▪正式版▪认证版▪第三方▪修改版▪测试版4驱动程序的开发▪微软平台▪Unix平台5安装顺序6inf文件1定义驱动程序(Device Driver)全称为“设备驱动程序”,是一种可以使计算机和设备通信的特殊程序,可以说相当于硬件的接口,操作系统只能通过这个接口,才能控制硬件设备的工作,假如某设备的驱动程序未能正确安装,便不能正常工作。
惠普显卡驱动安装正因为这个原因,驱动程序在系统中的所占的地位十分重要,一般当操作系统安装完毕后,首要的便是安装硬件设备的驱动程序。
不过,大多数情况下,我们并不需要安装所有硬件设备的驱动程序,例如硬盘、显示器、光驱等就不需要安装驱动程序,而显卡、声卡、扫描仪、摄像头、Modem等就需要安装驱动程序。
另外,不同版本的操作系统对硬件设备的支持也是不同的,一般情况下版本越高所支持的硬件设备也越多,例如笔者使用了Windows XP,装好系统后一个驱动程序也不用安装。
设备驱动程序用来将硬件本身的功能告诉操作系统,完成硬件设备电子信号与操作系统及软件的高级编程语言之间的互相翻译。
当操作系统需要使用某个硬件时,比如:让声卡播放音乐,它会先发送相应指令到声卡驱动程序,声卡驱动程序接收到后,马上将其翻译成声卡才能听懂的电子信号命令,从而让声卡播放音乐。
所以简单的说,驱动程序提供了硬件到操作系统的一个接口以及协调二者之间的关系,而因为驱动程序有如此重要的作用,所以人们都称“驱动程序是硬件的灵魂”、“硬件的主宰”,同时驱动程序也被形象的称为“硬件和系统之间的桥梁”。
内核复习提纲
⏹内核空间◆对于提供保护机制的现代系统来说,内核独立于普通应用程序,它一般处于系统态,拥有受保护的内存空间和访问硬件设备的所有权限。
这种系统态和被保护起来的内存空间,统称为内核空间。
⏹用户空间◆应用程序在用户空间执行。
它们只能看到允许它们使用的部分系统资源,并且不能使用某些特定的系统功能,不能直接访问硬件,还有其他一些使用限制。
当内核运行的时候,系统以内核态进入内核空间,相反,普通用户程序以用户态进入用户空间⏹进程上下文◆当一个应用程序请求执行一条系统调用,我们说内核正在代其执行。
进一步解释,应用程序被称为通过系统调用在内核空间运行,而内核被称为运行于进程上下文中。
这种交互关系——应用程序通过系统调用陷入内核——是应用程序完成其工作的基本行为方式。
⏹中断上下文◆许多操作系统的中断服务程序都不在进程上下文中执行。
它们在一个与所有进程都无关的、专门的中断上下文中运行。
◆这些上下文代表着内核活动的范围。
概括为下列三者之一:☐运行于内核空间,处于进程上下文,代表某个特定的进程执行。
☐运行干内核空间,处于中断上下文,与任何进程无关,处理某个特定的中断。
☐运行于用户空间,执行用户进程。
配置编译内核:$ tar zxvf linux-4.4.19.tar.gz在编译内核之前,首先你必须配置它。
由于内核提供了数不胜数的功能,支持了难以计数的硬件,因而有许多东西需要配置。
这些配置项要么是二选一,要么是三选一。
配置选项也可以是字符串或整数。
⏹内核提供了各种不同的工具来简化内核配置。
◆最简单的一种是一个基于文本的命令行工具:$make config☐该工具会挨个遍历所有配置项,要求用户选择yes、no或是module(如果是三选一的话)。
◆用基于ncurse库的图形界面工具:$make menuconfig◆用基于x11的图形工具:$make xconfig◆用基于gtk+图形工具:$make gconfig编译内核:配置完成后保存$ make -j2 V=1编译完后得到linux内核: arch/arm/boot/zImage内核开发的特点:◆内核编程时不能访问C库。
设备驱动程序简介
设备驱动程序简介1.设备驱动程序的作⽤从⼀个⾓度看,设备驱动程序的作⽤在于提供机制,⽽不是策略。
在编写驱动程序时,程序猿应该特别注意以下这个基本概念:编写訪问硬件的内核代码时,不要给⽤户强加不论什么特定策略。
由于不同的⽤户有不同的需求,驱动程序应该处理如何使硬件可⽤的问题。
⽽将如何使⽤硬件的问题留给上层应⽤程序。
从还有⼀个⾓度来看驱动程序。
它还能够看作是应⽤程序和实际设备之间的⼀个软件层。
总的来说,驱动程序设计主要还是综合考虑以下三个⽅⾯的因素:提供给⽤户尽量多的选项、编写驱动程序要占⽤的时间以及尽量保持程序简单⽽不⾄于错误丛⽣。
2.内核功能划分Unix系统⽀持多进程并发执⾏。
每⼀个进程都请求系统资源。
内核负责处理全部这些请求,依据内核完毕任务的不同,可将内核功能分为例如以下⼏部分:1.进程管理:负责创建和销魂进程。
并处理它们和外部世界之间的连接。
内核进程管理活动就是在单个或多个CPU上实现了多个进程的抽象。
2.内存管理:内存是计算机的主要资源之中的⼀个,⽤来管理内存的策略是决定系统系能的⼀个关键因素。
3.⽂件系统:内核在没有结构的硬件上构造结构化的⽂件系统。
⽽⽂件抽象在整个系统中⼴泛使⽤。
4.设备控制:差点⼉每个系统操作终于都会映射到物理设备上。
5.⽹络功能:⽹络功能也必须由操作系统来管理,系统负责在应⽤程序和⽹络接⼝之间传递数据包,并依据⽹络活动控制程序的运⾏。
全部的路由和地址解析问题都由内核处理。
可装载模块:Linux有⼀个⾮常好的特性:内核提供的特性可在执⾏时进⾏扩展。
可在执⾏时加⼊到内核的代码被称为“模块”。
Linux内核⽀持⼏种模块类型。
包含但不限于设备驱动程序。
每⼀个模块由⽬标代码组成,能够使⽤insmod程序将模块连接到正在执⾏的内核,也能够使⽤rmmod程序移除连接。
3.设备和模块的分类Linux系统将设备分成三个基本类型:字符设备、块设备、⽹络接⼝。
1.字符设备:字符设备驱动程序通常⾄少要实现open、close、read和write系统调⽤。
嵌入式Linux下GPIO驱动程序的开发及应用
第28卷第4期增刊 2007年4月仪 器 仪 表 学 报Chinese Jour nal of Scientif ic InstrumentVol.28No.4Apr.2007 嵌入式L inux 下GPIO 驱动程序的开发及应用3何 泉,贺玉梅(北京化工大学信息科学与技术学院 北京 100029)摘 要:嵌入式Linux 是一种适用于嵌入式系统的源码开放的占先式实时多任务操作系统,是目前操作系统领域中的一个热点,其重点与难点是驱动程序的开发。
开发嵌人式Linux 下的设备驱动程序,可以更好地利用新硬件特性,提高系统访问硬件的效率,改善整个应用系统的性能。
驱动程序修改非常方便,使应用系统非常灵活。
本文简要论述了基于A TM E L 公司嵌入式ARM 处理器芯片的嵌入式Linux 的GP IO 驱动程序的开发原理及流程。
关键词:嵌入式Linux ;ARM ;驱动程序;设备文件;GPIOInvest igat ion an d a pplicat ion of GP IO dr iver in t he embedded L inuxHe Quan ,He YuMei(School of I nf orma tion Science and Tec hnology BU CT ,Beij ing 100029,China )Abstract :Embedded Linu x ,w hich i s a full y real 2time kernel and applicable to embedded syst ems ,has bec o me a hot s 2po t in t he do main of op erati ng system at present.It s out line and difficult y is to investigat e drivers.Developi ng device dri vers o n embedded Lin ux can help using t he new devices ,and imp rovi ng t he e fficiency of access to t he new devices and t he p erformance cap abilit y.As drivers can be changed easil y ,t he system is very convenient and flexi ble.Thi s p a 2p er simpl y point s o ut t he element s and flow of t he GPIO driver in t he embedded Linux based o n t he A RM proces sor of A TMEL system.Key words :embedded Li nux ;A RM ;driver ;device file ;GPIO 3基金项目国家自然科学基金(6)、北京化工大学青年教师自然科学研究基金(QN 58)资助项目1 引 言随着半导体技术的飞速发展,嵌入式产品已经广泛应用于军事、消费电子、网络通信、工业控制等各个领域,这是嵌入式系统发展的必然趋势。
Windows系统如何进行驱动程序更新和安装
Windows系统如何进行驱动程序更新和安装作为一位Windows系统用户,你可能会遇到驱动程序需要更新或安装的情况。
驱动程序是系统与硬件设备之间的桥梁,保证硬件设备正常运行。
在本文中,我将为你介绍如何在Windows系统中进行驱动程序的更新和安装。
一、检查当前驱动程序的版本在更新或安装驱动程序之前,我们首先需要检查当前驱动程序的版本。
这可以帮助我们确定是否需要进行更新或安装。
下面是检查驱动程序版本的步骤:1. 打开“设备管理器”。
你可以通过按下"Win + X"键,在弹出的菜单中选择"设备管理器"打开。
2. 在设备管理器中,展开你想要检查的设备类别,例如:显示适配器、声音视频和游戏控制器等。
3. 右键点击你要检查的设备,选择“属性”。
4. 在设备属性窗口中,切换到“驱动程序”选项卡。
这里你可以看到当前驱动程序的版本号。
二、驱动程序更新的方法当我们确定需要更新驱动程序时,我们可以通过以下几种方法来进行更新:1. Windows更新Windows系统提供了自动更新驱动程序的功能。
你可以按照以下步骤进行操作:- 打开“设置”(Win + I),点击“更新和安全”。
- 在左侧导航栏中,选择“Windows更新”。
- 点击“检查更新”按钮,系统将自动检查可用的驱动程序更新,并且提示你进行安装。
2. 设备制造商官方网站在一些情况下,Windows更新可能无法提供最新的驱动程序更新。
这时,你可以前往设备制造商的官方网站,下载并安装最新的驱动程序。
你需要按照以下步骤进行操作:- 在浏览器中搜索设备制造商的官方网站。
- 寻找支持页面或下载页面,通常可以在网站的底部找到。
- 在支持或下载页面中,选择适合你设备型号和操作系统版本的驱动程序,并进行下载。
- 下载完成后,运行下载的文件,按照提示进行安装。
3. Windows驱动程序更新工具除了手动更新,你还可以使用一些Windows驱动程序更新工具来简化更新过程。
详解Linux操作系统设备驱动兼容性
floppy 45960 1 (autoclean)
floppy 45960 1 (autoclean)
EXPORT_SYMTAB;如果你打算引出一些符号,那么模块必须在包含之前定义这个宏。
EXPORT_SYMBOL(name);这个宏表明你想引出这个符号名。它必须在任何函数之外使用。
EXPORT_SYMBOL_NOVERS(name)使用这个宏而不是EXPORT_SYMBOL()强制丢弃版本信息,即使是编译带有版本支持的代码。这对避免一些不必要的重编译很有用。例如,memset函数将总以同样的方式工作;引出符号而不带版本信息允许开发者改变实现(甚至使用的数据类型)而不需insmod标出不兼容性。在模块化的代码中不大可能需要这个宏。
四个文件操作表征一个新的原型;它们是:
long long (*llseek) (struct inode *, struct file *, long long, int);
long (*read) (struct inode *, struct fle *, char *, unsigned long);
本章以重要性逐渐降低的顺序介绍不兼容;最重要的不同首先被介绍,次要的细节则在后面介绍。
模块化
在Linux社区中,模块化变的越来越重要,开发人员决定用一个更清晰的实现取代旧的。头文件在2.1.18中完全重写了,一个新的API被引入。如你所期望的,新的实现比旧的要容易使用。为了加载你的模块,你将需要包modutils-2.1.34甚至更新版本(细节见 Documentation/ Changes)。当与旧的核心一起使用时,这个包可以回到兼容模式,因此你可以用这个新包替换modules- 2.0.0,即使你经常在2.0和2.1之间切换。
嵌入式面试笔试题目——附部分答案
嵌⼊式⾯试笔试题⽬——附部分答案1 、如何⾃动创建设备⽂件?class_create device_create2、led驱动编写有⼏种⽅式?输⼊⼦系统字符设备驱动总线platform led⼦系统3、如何实现http服务器?tcp服务器:socket4、如何编写守护进程,简述syslog的作⽤?第⼀步:创建进程、杀死⽗进程第⼆步:创建新的会话第三步:改变⼯作路径路径第四步:修改⽂件掩码权限第五步:关闭⽂件描述符5、bootloader和uboot的区别?bootloader是启动装载。
这是⼀段很⼩的程序,⽤于在系统上电启动初期运⾏,初始化关键接⼝,如内存,串⼝,关闭中断,关闭看门狗,引导系统进⼊内核的⼀段初始化的程序。
它主要任务就是将内核映像从硬盘读到RAM中,然后跳转到内核的⼊⼝点去运⾏内核,从⽽建⽴系统运⾏的必要环境。
uboot:是bootloader的⼀种6、如何移植uboot?1、下载源码2、解压uboot源码并进⼊⽬录3、指定交叉编译⼯具链4、指定产品BOARD 底板5、编译u-boot7、传感器驱动如何编写?8、BL0,BL1,BL2,BL3的作⽤?BL0 ⽂件是存放在 CPU 内部 IROM 中的⼀段固化代码,CPU 上点之后,⾸先去运⾏soc中的BL0,运⾏时会将 BL1 拷贝到 CPU 的 IRAM 中,然后执⾏BL1;BL1⽂件执⾏起来之后会先进⾏内存的初始化,之后将 BL2 ⽂件拷贝到外部内存中,BL2会初始化BL3的运⾏环境,将BL3搬移到DRAM中,BL3会有⼀个⾃搬移的过程,从⽽启动内核⼊⼝。
BL0:CPU内部的固化代码BL1:三星提供的加密⽂件BL2:截取uboot.bin 前14kBL3:剩下的uboot 执⾏命令以及加载引导内核9、exynos4412 时钟 APLL,MPLL,VPLL的区别?------倍频锁相环APLL:⽤于 CPU_BLK (可产⽣⾼达1.4GHz的频率);作为 MPLL 的补充,它也可以给DMC_BLK 、LEFTBUS_BLK 、RIGHTBUS_BLK 和 CMU_TOP 提供时钟。
Windows 95下的虚拟设备驱动程序
Windows 95下的虚拟设备驱动程序虚拟设备驱动程序(VxDs)在很大程度上支持了Windows 3.x和Windows 95。
通常,我们从两个级别的意义上来认识VxDs:从低级意义上来说,它们直接存取系统的硬件;而从高级意义上来看,它们在最高优先级别上运行。
在Windows 95中,VxDs显得更加重要,Microsoft正是靠VxDs扩展了操作系统内核的处理能力。
Win 95中的VxDs可以处理涉及从文件系统到声卡以至网络系统的各种事务。
可能您还未认识到:尽管VxDs本身是32位的,但它却诞生于16位的非线程、非抢占性的操作系统。
而现在人们期待甚至要求VxDs能运作于具有线程化、可抢占性的操作系统,简单的变形是不能解决此问题的。
虚拟机假想一台虚拟机(VM)只不过是人们的一个假想。
而特别的,这个假想认为一个给定的进程可对一台计算机的所有硬件设备进行独占性的存取,这些设备包括了内存、I/O口、中断和其它进程想要占用的部件。
VxDs就是为了此假想产生的。
Windows 3.1中有两种虚拟机(VMs):DOS壳和Windows VM本身(后者称为"系统虚拟机"———所有的Windows应用程序运行于其中)。
而虚拟机管理器(VMM),尽管它本身不是一VM,但却充当着激活VMs和VxDs的主要管理员。
例如,VMM要处理在运行VMs时的抢占时间片工作。
另外,任何用来虚拟管理I/O设备的VxD都必须在VMM中登记。
因此,如果一VxD要占用一些特殊的I/O端口,就必须请求VMM挂起这个端口。
这样,无论何时当一Windows应用程序试图对此口进行存取操作时,VMM将把这个存取请求传给特定的VxD。
在Win 95中这样的情况基本相同,但做得更好。
仍然是DOS壳作为一VM,所有的Windows进程作为一VM。
但这些进程包含了一些比Windows 3.x中的Win32s程序具有更强能力的Win32应用程序。
计算机操作系统课后答案第9章习题解答
第9章习题解答一、填空1.MS-DOS操作系统由BOOT、IO.SYS、MSDOS.SYS以及 所组成。
2.MS-DOS的一个进程,由程序(包括代码、数据和堆栈)、程序段前缀以及环境块三部分组成。
3.MS-DOS向用户提供了两种控制作业运行的方式,一种是批处理方式,一种是命令处理方式。
4.MS-DOS存储管理规定,从地址0开始每16个字节为一个“节”,它是进行存储分配的单位。
5.MS-DOS在每个内存分区的前面都开辟一个16个字节的区域,在它里面存放该分区的尺寸和使用信息。
这个区域被称为是一个内存分区所对应的内存控制块。
6.MS-DOS有4个存储区域,它们是:常规内存区、上位内存区、高端内存区和扩充内存区。
7.“簇”是MS-DOS进行磁盘存储空间分配的单位,它所含扇区数必须是2的整数次方。
8.当一个目录表里仅包含“.”和“..”时,意味该目录表为空。
9.在MS-DOS里,用文件名打开文件,随后就通过句柄来访问该文件了。
10.在MS-DOS里,把字符设备视为设备文件。
二、选择1.下面对DOS的说法中,B 是正确的。
A.内、外部命令都常驻内存B.内部命令常驻内存,外部命令非常驻内存C.内、外部命令都非常驻内存D.内部命令非常驻内存,外部命令常驻内存2.DOS进程的程序,在内存里 D 存放在一起。
A.总是和程序段前缀以及环境块B.和谁都不C.总是和进程的环境块D.总是和程序段前缀3.MS-DOS启动时能够自动执行的批处理文件名是: C 。
A.CONFIG.SYS B.MSDOS.SYSC.AUTOEXEC.BAT D.4.下面所列的内存分配算法, D 不是MS-DOS采用的。
A.最佳适应法B.最先适应法C.最后适应法D.最坏适应法5.在MS-DOS里,从1024K到1088K的存储区域被称为 D 区。
A.上位内存B.扩展内存C.扩充内存D.高端内存6.MS-DOS的存储管理是对A的管理。
A.常规内存B.常规内存和上位内存C.常规内存和扩展内存D.常规内存和扩充内存7.在下面给出的MS-DOS常用扩展名中,B 不表示一个可执行文件。
linux字符驱动框架(用户态的read,write,poll是怎么操作驱动的)
linux字符驱动框架(⽤户态的read,write,poll是怎么操作驱动的)前⾔这篇⽂章是通过对⼀个简单字符设备驱动的操作来解释,⽤户态的读写操作是怎么映射到具体设备的。
因为针对不同版本的linux内核,驱动的接⼝函数⼀直有变化,这贴出我测试的系统信息:root@ubuntu:~/share/dev/cdev-2# cat /etc/os-release |grep -i verVERSION="16.04.5 LTS (Xenial Xerus)"VERSION_ID="16.04"VERSION_CODENAME=xenialroot@ubuntu:~/share/dev/cdev-2#root@ubuntu:~/share/dev/cdev-2# uname -r4.15.0-33-generic字符驱动这⾥给出了⼀个不怎么标准的驱动,定义了⼀个结构体 struct dev,其中buffer成员模拟驱动的寄存器。
由wr,rd作为读写指针,len作为缓存buffer的长度。
具体步骤如下:1. 定义 init 函数,exit函数,这是在 insmod,rmmod时候调⽤的。
2. 定义驱动打开函数open,这是在⽤户态打开设备时候调⽤的。
3. 定义release函数,这是在⽤户态关闭设备时候⽤到的。
4. 定义read,write,poll函数,并挂接到 file_operations结构体中,所有⽤户态的read,write,poll都会最终调到这些函数。
chardev.c/*参考:深⼊浅出linux设备驱动开发*/#include <linux/module.h>#include <linux/init.h>#include <linux/fs.h>#include <linux/uaccess.h>#include <linux/wait.h>#include <linux/semaphore.h>#include <linux/sched.h>#include <linux/cdev.h>#include <linux/types.h>#include <linux/kdev_t.h>#include <linux/device.h>#include <linux/poll.h>#define MAXNUM 100#define MAJOR_NUM 400 //主设备号 ,没有被使⽤struct dev{struct cdev devm; //字符设备struct semaphore sem;int flag;poll_table* table;wait_queue_head_t outq;//等待队列,实现阻塞操作char buffer[MAXNUM+1]; //字符缓冲区char *rd,*wr,*end; //读,写,尾指针}globalvar;static struct class *my_class;int major=MAJOR_NUM;static ssize_t globalvar_read(struct file *,char *,size_t ,loff_t *);static ssize_t globalvar_write(struct file *,const char *,size_t ,loff_t *);static int globalvar_open(struct inode *inode,struct file *filp);static int globalvar_release(struct inode *inode,struct file *filp);static unsigned int globalvar_poll(struct file* filp, poll_table* wait);/*结构体file_operations在头⽂件 linux/fs.h中定义,⽤来存储驱动内核模块提供的对设备进⾏各种操作的函数的指针。
ioctl write read
文章标题:深度解析ioctl write read及其在操作系统中的应用在操作系统中,ioctl write read是一个重要的系统调用,用于设备驱动程序和用户空间程序之间进行通信和数据传输。
它涉及到设备的读写操作,以及参数的传递和数据的交换,对于理解操作系统的基本原理和内部机制具有重要意义。
一、ioctl write read的基本概念和原理1. ioctl write read的定义和功能ioctl write read是一种用于设备驱动程序的系统调用,它允许用户空间程序向设备发出控制命令(ioctl write)或者进行数据读写(ioctl read),从而实现设备的配置、状态查询和数据交换等操作。
2. ioctl write read的调用方式和参数ioctl write read的调用通常需要指定设备文件描述符、ioctl命令码和参数指针等信息,以便设备驱动程序正确解析并执行用户空间程序的请求。
3. ioctl write read的内部实现和机制ioctl write read的内部实现涉及到系统调用的传递和参数的解析,以及设备驱动程序的响应和数据传输,需要通过对操作系统内部结构和调度机制的理解才能深入掌握其工作原理。
二、ioctl write read的应用场景和实际意义1. 设备驱动程序中的ioctl write read使用在设备驱动程序中,ioctl write read常用于设备的配置和控制,以及数据的读写和传输,例如网络设备的设置、字符设备的输入输出等。
2. 用户空间程序中的ioctl write read调用在用户空间程序中,ioctl write read可以用于与设备驱动程序进行通信和交互,实现设备的操作和功能扩展,例如串口通信、USB设备控制等。
三、个人观点和理解从我个人的理解来看,ioctl write read是操作系统中一个重要的系统调用,它为设备驱动程序和用户空间程序之间的通信提供了灵活和强大的接口,有利于实现设备的功能扩展和应用开发。
2022年广西师范大学数据科学与大数据技术专业《操作系统》科目期末试卷A(有答案)
2022年广西师范大学数据科学与大数据技术专业《操作系统》科目期末试卷A(有答案)一、选择题1、设计实时操作系统时,首先应该考虑系统的()。
A.可靠性和灵活性B.实时性和可靠性C.分配性和可靠性D.灵活性和实时性2、与早期的操作系统相比,采用微内核结构的操作系统具有很多优点,但是这些优点不,包括()。
A.提高了系统的可扩展性B.提高了操作系统的运行效率C.增强了系统的可靠性D.使操作系统的可移植性更好3、某计算机系统中有8台打印机,有K个进程竞争使用,每个进,程最多需要3台打印机,该系统可能会发生死锁的K的最小值是()A.2B.3C.4D.54、下列关于进程和线程的叙述中,正确的是()A.不管系统是否支持线程,进程都是资源分配的基本单位,B.线程是资源分配的基本单位,进程是调度的基本单位C.系统级线程和用户级线程的切换都需要内核的支持D.同一进程中的各个线程拥有各自不同的地址空间5、在下列操作系统的各个功能组成部分中,一定需要专门硬件配合支持的是()。
I.地址映射III.中断系统IV.系统调用A.IB.I、IIIC. I、III、IVD.II、II6、下面设备中属于共享设备的是()。
A.打印机B.磁带机C.磁盘D.磁带机和磁盘7、某进程的段表内容见表,当访问段号为2、段内地址为400的逻辑地址时,进行地址转换的结果是()。
A.段缺失异常B.得到内存地址4400C.越权异常D.越界异常8、下列关厂索引表的叙述中,正确的是()。
A.索引表中每个记录的索引项可以有多个B.对索引文件存取时,必须先查找索引表C.索引表中含有索引文件的数据及其物理地址D.建立索引表的i1的之,是减少存储空间,9、下列文件物理结构中,适合随机访问且易于文件扩展的是()。
B.索引结构C.链式结构且磁盘块定长D.链式结构且磁盘块变长10、设系统缓冲区和用户工作区均采用单缓冲,从外设读入一个数据块到系统缓冲区的时间为100,从系统缓冲区读入1个数据块到用户工作区的时间为5,对用户上作区中的1个数据块进行分析的时问为90。
inf文件是什么
对应到图usbinfpng.png中,就是这行语句“%GenericBulkOnly.DeviceDesc%=USBSTOR_BULK, USB\Class_08&SubClass_02&Prot_50”等号左边是设备的描述,也就是设备名字是"USB Mass Storage Device",而等号右边的USB\Class_08&SubClass_02&Prot_50是设备标志符,这个标志符是对应到一类的硬件设备,就是USB存储设备,操作系统检测到USB存储设备,安装相应的驱动的时候,就会从设备驱动的安装节即[USBSTOR_BULK]节开始安装驱动。可以看出来此.INF文件可以用于通用的USB存储设备"USB Mass Storage Device"的驱动程序的安装。
[manufacturer-name]
device-description=install-section-name,device-id[,compatible-device-id]...
device-description就是对要安装的设备的描述。install-section-name就是此设备的 [Install] 节区名称,manufacturer-name 节区名称必须已在 [Manufacturer] 节区中被定义。device-id是此设备的硬件标志符,每个厂家的不同的硬件对应着不同的设备标志符。
加工中心基本操作
加工中心基本操作
位置界面
说明:按“POS”健即进入位置界面,位置界面主要显示当前的各种坐标
信息,
加工中心基本操作
说明:在位置界面可以显示当前机床的绝对坐标、相对坐标以及综合坐标
加工中心基本操作
程序界面
说明:按“PROG”键,即进入程序界面,在程序界面可以进行程序的新建、 编程、删除、调用和传输等操作。
使用手轮进给轴选择按钮选择要移动的轴,轴移 动速度由手摇脉冲发生器转速控制,超过轴最高运 动的脉冲将被忽略。 手轮方式主要用来进行工件的对刀。
加工中心基本操作
使用外挂手持盒,使机床操作者可以更贴近工件加工区移动伺 服轴,从而更加方便于对刀等近距离操作的情况。
悬挂手挂
使用步骤: 1)操作面板的工作方式选择开关SA1旋转至手轮 方式(×1,×10,×100); 2)手握外挂手持盒,选择要移动的有效伺服轴 ( X或 Z) 3)一手按外挂手持盒侧面的按纽,此时手持盒指 示灯变亮,表示可以操作; 4)另一手可以旋转手轮移动机床轴; 5)当遇有紧急情况时,可以按外挂手持盒上面的 急停按钮,机床处于急停状态;
在机床锁定生效后只要轴移动过务必手动回参考点否则机床如果执行自动循环有可能出现误动作这会造成刀具机床本身的损坏甚至伤及人加工中心基本操作该功能用于指定刀具断裂或公休后重新启动程序时将要启动程序段的顺序号从该段程序重新启动机床也可以用于高速程序检查
立加“裸体”+“外形”图
Z+ X+ Y+
屏幕显示区
加工中心基本操作
在连续进给方式下按下此按钮,转台将先执 行机床回零,回零结束后进行转台放松,转 位,锁紧,复位,转台分度过程中指示灯亮。 注:选配A轴时该按钮为分度盘放松指示, 指 示灯亮分度盘可转动。.
QNX的字符IO
QNX的字符IO一、简介字符设备是一种通过一组串行字节进行IO操作的设备,与块设备(如硬盘)不同。
PC上的典型字符设备有:・serial ports:串口・parallel ports:并口・text-mode consoles:字符模式的控制台・pseudo terminals(ptys):虚拟终端程序通常使用标准的open()、close()、read()、write() API来操作字符设备。
一些附加的函数用于操作字符设备的特有属性,如传送速度(baud rate),奇偶性(parity),流控制(flow control)等。
字符设备的共享库为io-char。
1、Driver / io-char communication[驱动与io-char之间的通信]io-char库管理程序与设备之间的数据流,它是通过分配给每个字符设备的内存队列(memory queues)进行数据传输。
每个字符设备会被分配三个先进先出队列。
接受的数据会被驱动程序放到输入队列(input queue)中,当程序需要数据时由io-char消费。
驱动程序中的中端处理通常会通过调用io-char中提供的机能将数据添加到输入队列中。
这能够保证输入处理的统一性,并较少驱动的职责。
io-char将输出数据放入输出队列中,由驱动程序将其传输给设备。
只有当输出队列满的时候,io-char才会阻塞用户进程。
标准队列(canonical queue)由io-char管理,由于处理在编辑模式中的输入数据。
这个队列的大小决定了特定设备能够编辑的输入行的大小。
所有这些队列的大小都可以通过命令行来修改,它们的默认值通常都比硬件的配置来的大一点,但你可以减少它们以降低整个系统的内存需求。
设备驱动只是将输入数据添加到输入队列,并将输出队列中的数据传输给设备。
io-char决定何时、如何阻塞输出处理,如何响应接受的数据等。
2、Device control[设备控制]底层设备的控制通过devctl()来实现。
ioctl介绍
ioctl介绍什么是ioctl?ioctl是一个系统调用,用于设备的控制和配置。
它是英文Input/Output Control 的缩写,意味着它可以用来对设备的输入和输出进行控制。
ioctl提供了一种通用的接口,可以用于访问和操作各种设备,包括字符设备、块设备和网络设备等。
ioctl的工作原理在Linux系统中,设备通常以文件的形式表示,而ioctl则是通过文件描述符来操作这些设备。
ioctl函数的原型如下:int ioctl(int fd, unsigned long request, ...);其中,fd是一个文件描述符,request是一个无符号长整型的控制命令,后面的省略号表示可选的参数。
ioctl函数的返回值为0表示成功,-1表示失败。
ioctl函数的工作原理如下:1.应用程序调用ioctl函数,将设备的文件描述符、控制命令和可选参数传递给内核。
2.内核根据控制命令,将请求转发给相应的设备驱动程序。
3.设备驱动程序根据控制命令的具体要求,对设备进行相应的操作。
4.设备驱动程序将操作结果返回给内核。
5.内核将操作结果返回给应用程序。
ioctl的应用场景ioctl广泛应用于各种设备的控制和配置。
以下是一些常见的应用场景:1. 字符设备的控制字符设备是一种按字符进行输入和输出的设备,如终端、串口等。
通过ioctl,可以对字符设备进行各种控制和配置,例如设置终端的行数和列数、设置串口的波特率等。
2. 块设备的控制块设备是一种按块进行输入和输出的设备,如硬盘、闪存等。
通过ioctl,可以对块设备进行各种控制和配置,例如格式化磁盘、设置磁盘的几何参数等。
3. 网络设备的控制网络设备是一种用于数据通信的设备,如网卡、调制解调器等。
通过ioctl,可以对网络设备进行各种控制和配置,例如设置网卡的IP地址、设置网卡的MTU等。
4. 文件系统的控制文件系统是一种用于组织和管理文件的数据结构,如ext4、NTFS等。
操作系统期末考试复习题
复习题一、选择题1.若把操作系统看作计算机系统资源的管理者,下列(D )不属于操作系统所管理的资源。
A.程序B.内存C.CPUD.中断2.通道是一种(C )。
A.I/O端口 B.数据通道C. I/O专用处理器D软件工具3、如果I/O设备与存储设备进行数据交换不经过CPU来完成,这种数据交换方式是( C )。
A.程序查询B.中断方式C.DMA方式D.无条件存取方式4、文件系统中用(C )管理文件。
A.作业控制块B.索引C.目录D.软硬件结合的方法5、常用的文件存取方法有两种,顺序存取和(C )存取。
A.流式B. 串联C.随机D.索引6、.作业在后备队列一旦被调度程序选中,作业就处于(B)状态。
A.提交B.执行C.完成D.收容7.(A )是指从作业提交到给系统到作业完成的时间段。
A.周转时间B.响应时间C.等待时间D. 触发时间8.缓冲技术的缓冲池在(A)。
A.内存B.外存C.ROMD.寄存器9.按文件的逻辑结构划分,文件分为记录式文件和( C )文件。
A.索引文件 B.流式文件C.字符流式文件 D.读写文件10.( B )是作业存在的唯一标志。
A.作业名B.作业控制块C.程序名 D进程控制块11.分配到必要资源,并获得处理机的进程状态是(B )。
A.就绪状态B.执行状态C.阻塞状态D.撤销状态12.在进程管理中,当(B)时,进程从阻塞状态变为就绪状态。
A.进程被进程调度程序选中B.等待某一事件发生C.等待某一事件D.时间片到13.进程的并发执行是指若干进程(D )。
A.同时执行B.执行时间不可重叠C.共享资源D.执行时间上重叠14.下列进程状态,(C )变化是不可能发生的。
A.执行—>就绪B.执行—>等待C.等待—>执行D.等待—>就绪15.作业调度从处于(D )状态的队列由选取适当的作业投入运行。
A.运行B.提交C.完成D.后备16.在存储管理中,采用覆盖技术与交换技术的目的是( A)。
CAN总线在嵌入式Linux下驱动程序的实现
CAN总线在嵌⼊式Linux下驱动程序的实现 1引⾔ 基于嵌⼊式系统设计的⼯业控制装置,在⼯业控制现场受到各种⼲扰,如电磁、粉尘、天⽓等对系统的正常运⾏造成很⼤的影响。
在⼯业控制现场各个设备之间要经常交换、传输数据,需要⼀种抗⼲扰性强、稳定、传输速率快的现场进⾏通信。
⽂章采⽤,基于嵌⼊式系统32位的,通过其SPI, CAN扩展CAN;将嵌⼊式操作系统嵌⼊到S3C44B0X微中,能实现多任务、友好图形⽤户界⾯;针对S3C44B0X微处理器没有管理单元MMU,采⽤uClinux嵌⼊式操作系统。
这样在嵌⼊式系统中扩展CAN设备关键技术就是CAN设备在嵌⼊式操作系统下驱动程序的实现。
⽂章重点解决了CAN总线在嵌⼊式操作系统下驱动程序实现的问题。
对于⽤户来说,CAN设备在嵌⼊式操作系统驱动的实现为⽤户屏蔽了硬件的细节,⽤户不⽤关⼼硬件就可以编出⾃⼰的⽤户程序。
实验结果表明驱动程序的正确性,能提⾼整个系统的抗⼲扰能⼒,稳定性好,最⼤传输速率达到1Mb/s;硬件的错误检定特性也增强了CAN的抗电磁⼲扰能⼒。
2系统硬件设计 系统采⽤S3C44B0X微处理器,需要扩展CAN控制器。
常⽤的CAN控制器有和,这两种都⽀持CAN2.0B标准。
SJA1000采⽤的总线是地址线和复⽤的⽅式,但是嵌⼊式处理器外部总线⼤多是地址线和数据线分开的结构,这样每次对SJA1000操作时需要先后写⼊地址和数据2次数据,⽽且SJA1000使⽤5V逻辑电平。
所以应⽤MCP2510控制器进⾏扩展,采⽤。
MCP2510控制器特点:1.⽀持标准格式和扩展格式的CAN数据帧结构(CAN2.0B);2.0~8字节的有效数据长度,⽀持远程帧;3.最⼤1Mb/s的可编程波特率;4.2个⽀持过滤器的接受缓冲区,3个发送缓冲区;5.SPI⾼速串⾏总线,最⼤;6.3~5.5V宽电压范围供电。
MCP2510⼯作电压为,能够直接与S3C44B0X微处理器I/O⼝相连。
Linux设备驱动开发详解-第6章字符设备驱动(一)-globalmem
Linux设备驱动开发详解-第6章字符设备驱动(⼀)-globalmem1 驱动程序设计之前奏 (2)1.1 应⽤程序、库、内核、驱动程序的关系 (2)1.2 设备类型 (2)1.3 设备⽂件 (2)1.4 主设备号和从设备号 (2)1.5 驱动程序与应⽤程序的区别 (3)1.6 ⽤户态与内核态 (3)1.7 Linux驱动程序功能 (3)2 字符设备驱动程序框架 (3)2.1 file_operations结构体 (4)2.2 驱动程序初始化和退出 (5)2.3 将驱动程序模块注册到内核 (5)2.4 应⽤字符设备驱动程序 (5)3 globalmem虚拟设备实例描述 (6)3.1 头⽂件、宏及设备结构体 (6)3.2 加载与卸载设备驱动 (6)3.3 读写函数 (8)3.4 seek()函数 (9)3.5 ioctl()函数 (10)3.6 globalmem完整实例 (12)4 测试应⽤程序 (17)4.1 应⽤程序接⼝函数 (17)4.2 应⽤程序 (18)5 实验步骤 (19)5.1 编译加载globalmem 模块 (19)5.2 编译测试应⽤程序 (20)6 扩展 (21)1 驱动程序设计之前奏㈠应⽤程序、库、内核、驱动程序的关系㈡设备类型㈢设备⽂件㈣主设备号与从设备号㈤驱动程序与应⽤程序的区别㈥⽤户态与内核态㈦Linux驱动程序功能1.1 应⽤程序、库、内核、驱动程序的关系■应⽤程序调⽤应⽤程序函数库完成功能■应⽤程序以⽂件形式访问各种资源■应⽤程序函数库部分函数直接完成功能部分函数通过系统调⽤由内核完成■内核处理系统调⽤,调⽤设备驱动程序■设备驱动直接与硬件通信1.2 设备类型■字符设备对字符设备发出读/写请求时,实际的硬件I/O操作⼀般紧接着发⽣■块设备块设备与之相反,它利⽤系统内存作为缓冲区■⽹络设备⽹络设备是⼀类特殊的设备,它不像字符设备或块设备那样通过对应的设备⽂件节点访问,也不能直接通过read或write进⾏数据访问请求1.3 设备⽂件■设备类型、主从设备号是内核与设备驱动程序通信时使⽤的■应⽤程序使⽤设备⽂件节点访问对应设备■每个主从设备号确定的设备都对应⼀个⽂件节点■每个设备⽂件都有其⽂件属性(c或者b)■每个设备⽂件都有2个设备号(后⾯详述)主设备号:⽤于标识驱动程序从设备号:⽤于标识同⼀驱动程序的不同硬件■设备⽂件的主设备号必须与设备驱动程序在登记时申请的主设备号⼀致■系统调⽤是内核与应⽤程序之间的接⼝■设备驱动程序是内核与硬件之间的接⼝1.4 主设备号和从设备号■在设备管理中,除了设备类型外,内核还需要⼀对被称为主从设备号的参数,才能唯⼀标识⼀个设备■主设备号相同的设备使⽤相同的驱动程序■从设备号⽤于区分具体设备的实例例:PC的IDE设备,主设备号⽤于标识该硬盘,从设备号⽤于标识每个分区■在/dev⽬录下使⽤ll命令(ls -l)可以查看各个设备的设备类型、主从设备号等■cat /proc/devices可以查看系统中所有设备对应的主设备号1.5 驱动程序与应⽤程序的区别■应⽤程序以main开始■驱动程序没有main,它以⼀个模块初始化函数作为⼊⼝■应⽤程序从头到尾执⾏⼀个任务■驱动程序完成初始化之后不再运⾏,等待系统调⽤■应⽤程序可以使⽤GLIBC等标准C函数库■驱动程序不能使⽤标准C库1.6 ⽤户态与内核态■驱动程序是内核的⼀部分,⼯作在内核态■应⽤程序⼯作在⽤户态■数据空间访问问题★⽆法通过指针直接将⼆者的数据地址进⾏传递★系统提供⼀系列函数帮助完成数据空间转换get_userput_usercopy_from_usercopy_to_user1.7 Linux驱动程序功能■对设备初始化和释放■把数据从内核传送到硬件和从硬件读取数据■读取应⽤程序传送给设备⽂件的数据和回送应⽤程序请求的数据■检测和处理设备出现的错误2 字符设备驱动程序框架①Linux各种设备驱动程序都是以模块的形式存在的,驱动程序同样遵循模块编程的各项原则②字符设备是最基本、最常⽤的设备,其本质就是将千差万别的各种硬件设备采⽤⼀个统⼀的接⼝封装起来,屏蔽了不同设备之间使⽤上的差异性,简化了应⽤层对硬件的操作③字符设备将各底层硬件设备封装成统⼀的结构体,并采⽤相同的函数操作,如下等:open/close/read/write/ioctl④添加⼀个字符设备驱动程序,实际上是给上述操作添加对应的代码⑤Linux对所有的硬件操作统⼀做以下抽象抽象file_operations结构体规定了驱动程序向应⽤程序提供的操作接⼝struct file_operations ext2_file_operations ={.llseek = generic_file_llseek,.read = generic_file_read,.write = generic_file_write,.aio_read = generic_file_aio_read,.aio_write = generic_file_aio_write,.ioctl = ext2_ioctl,.mmap = generic_file_mmap,.open = generic_file_open,.release = ext2_release_file,.fsync = ext2_sync_file,.readv = generic_file_readv,.writev = generic_file_writev,.sendfile = generic_file_sendfile,};⑥⽤户态与内核态数据的交互⽤户应⽤程序与驱动程序分属于不同的进程空间,因此⼆者之间的数据应当采⽤以下函数进⾏交换long copy_to_user(kernel_buffer, user_buffer,n)//从内核空间拷贝n字节数据到⽤户空间copy_from_user(kernel_buffer, user_buffer,n)//从⽤户空间拷贝n字节数据到内核空间put_user(kernel_value, user_buffer)//从内核空间拷贝⼀数据变量到⽤户空间get_user(kernel_value, user_buffer)//从⽤户空间拷贝⼀数据变量到内核空间(内核空间数据可是任意类型)2.1 file_operations结构体⑴write函数■从应⽤程序接收数据送到硬件ssize_t (*write)(struct file*, const char __user *, size_t, loff_t*);⑵read函数■从硬件读取数据并交给应⽤程序ssize_t (*read)(struct file *, char __user *, size_t, loff_t*); /// 从设备中同步读取数据⑶ioctl函数■为应⽤程序提供对硬件⾏为的相关配置int (*ioctl)(struct inode *, struct file *, unsigned int, unsigned long);⑷open函数■当应⽤程序打开设备时对设备进⾏初始化■使⽤MOD_INC_USE_COUNT增加驱动程序的使⽤次数,当模块使⽤次数不为0时,禁⽌卸载模块Int (*open)(struct inode *, struct file*);⑸release函数■当应⽤程序关闭设备时处理设备的关闭操作■使⽤MOD_DEC_USE_COUNT减少驱动程序的使⽤次数,配合open使⽤,来对模块使⽤次数进⾏计数int (*release)(struct inode *, struct file*);⑹⑻⑻⑼⑽2.2 驱动程序初始化和退出①驱动程序初始化函数■Linux在加载内核模块时会调⽤初始化函数■在初始化函数中⾸先进⾏资源申请等⼯作■使⽤register_chrdev向内核注册驱动程序②驱动程序退出函数■Linux在卸载内核模块时会调⽤退出函数■释放驱动程序使⽤的资源■使⽤unregister_chrdev从内核中卸载驱动程序2.3 将驱动程序模块注册到内核内核需要知道模块的初始化函数和退出函数,才能将模块放⼊⾃⼰的管理队列中①module_init()向内核声明当前模块的初始化函数②module_exit()向内核声明当前模块的退出函数2.4 应⽤字符设备驱动程序㈠加载驱动程序■insmod 内核模块⽂件名■cat /proc/devices 查看当前系统中所有设备驱动程序及其主设备号㈡⼿动建⽴设备⽂件■设备⽂件⼀般建⽴/dev⽬录下■mknod ⽂件路径c [主设备号] [从设备号]㈢应⽤程序接⼝函数■编写应⽤层测试程序■可以使⽤标准C的⽂件操作函数来完成①int open(const char *path, int oflag,…);★打开名为path的⽂件或设备★成功打开后返回⽂件句柄★常⽤oflag:O_RDONLY, O_WRONLY, O_RDWR②int close(int fd);★关闭之前被打开的⽂件或设备★成功关闭返回0,否则返回错误代号③ssize_t read(int fd, void *buffer, size_t count)★从已经打开的⽂件或设备中读取数据★buffer表⽰应⽤程序缓冲区★count表⽰应⽤程序希望读取的数据长度★成功读取后返回读取的字节数,否则返回-1④ssize_t write(int fd, void *buffer, size_t count);★向已经打开的⽂件或设备中写⼊数据★buffer表⽰应⽤程序缓冲区★count表⽰应⽤程序希望写⼊的数据长度★成功写⼊后返回写⼊的字节数,否则返回-1④int ioctl(int fd, unsigned int cmd, unsigned long arg);★向驱动程序发送控制命令★cmd:⽤来定义⽤户向驱动分配的命令例如G PF驱动中:设置指定管脚的⾼低电平、输⼊输出特性等为了规范化及错误检查常⽤_IO宏合成该命令:_IO(MAGIC, num) ★arg:配置命令参数配合cmd命令完成指定功能3 globalmem虚拟设备实例描述3.1 头⽂件、宏及设备结构体在globalmem字符设备驱动中,应包含它要使⽤的头⽂件,并定义globalmem设备结构体及相关宏。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
第5章字符设备驱动程序的扩展操作在关于字符设备驱动程序的那一章中,我们构建了一个完整的设备驱动程序,从中用户可以读也可以写。
但实际一个驱动程序通常会提供比同步read和write更多的功能。
现在如果出了什么毛病,我已经配备了调试工具,我们可以大胆的实验并实现新操作。
通过补充设备读写操作的功能之一就是控制硬件,最常用的通过设备驱动程序完成控制动作的方法就是实现ioctl方法。
另一种方法是检查写到设备中的数据流,使用特殊序列做为控制命令。
尽管有时也使用后者,但应该尽量避免这样使用。
不过稍后我们还是会在本章的“非ioctl设备控制”一节中介绍这项技术。
正如我在前一章中所猜想的,ioctl系统调用为驱动程序执行“命令”提供了一个设备相关的入口点。
与read和其他方法不同,ioctl是设备相关的,它允许应用程序访问被驱动硬件的特殊功能――配置设备以及进入或退出操作模式。
这些“控制操作”通常无法通过read/write文件操作完成。
例如,你向串口写的所有数据都通过串口发送出去了,你无法通过写设备改变波特率。
这就是ioctl所要做的:控制I/O通道。
实际设备(与scull不同)的另一个重要功能是,读或写的数据需要同其他硬件交互,需要某些同步机制。
阻塞型I/O和异步触发的概念将满足这些需求,本章将通过一个改写的scull设备介绍这些内容。
驱动程序利用不同进程间的交互产生异步事件。
与最初的scull相同,你无需特殊硬件来测试驱动程序是否可以工作。
直到第8章“硬件管理”我才会真正去与硬件打交道。
ioctl在用户空间内调用ioctl函数的原型大致如下:int ioctl(int fd, int cmd, ...);由于使用了一连串的“.”的缘故,该原型在Unix系统调用列表之中非常突出,这些点代表可变数目参数。
但是在实际系统中,系统调用实际上不会有可变数目个参数。
因为用户程序只能通过第2章“编写和运行模块”的“用户空间和内核空间”一节中介绍的硬件“门”才能访问内核,系统调用必须有精确定义的参数个数。
因此,ioctl的第3个参数事实上只是一个可选参数,这里用点只是为了在编译时防止编译器进行类型检查。
第3个参数的具体情况与要完成的控制命令(第2个参数)有关。
某些命令不需要参数,某些需要一个整数做参数,而某些则需要一个指针做参数。
使用指针通常是可以用来向ioctl传递任意数目数据;设备可以从用户空间接收任意大小的数据。
系统调用的参数根据方法的声明传递给驱动程序方法:int (*ioctl) (struct inode *inode, struct file *filp,unsigned int cmd, unsigned long arg) inode和filp指针是根据应用程序传递的文件描述符fd计算而得的,与read和write的用法一致。
参数cmd不经修改地传递给驱动程序,可选的arg参数无论是指针还是整数值,它都以unsigned long的形式传递给驱动程序。
如果调用程序没有传递第3个参数,驱动程序所接收的arg没有任何意义。
由于附加参数的类型检查被关闭了,如果非法参数传递给ioctl,编译器无法向你报警,程序员在运行前是无法注意这个错误的。
这是我所见到的ioctl语义方面的唯一一个问题。
如你所想,大多数ioctl实现都包括一个switch语句来根据cmd参数选择正确的操作。
不同的命令对应不同的数值,为了简化代码我们通常会使用符号名代替数值。
这些符号名都是在预处理中赋值的。
不同的驱动程序通常会在它们的头文件中声明这些符号;scull就在scull.h中声明了这些符号。
选择ioctl命令在编写ioctl代码之前,你需要选择对应不同命令的命令号。
遗憾的是,简单地从1开始选择号码是不能奏效的。
为了防止对错误的设备使用正确的命令,命令号应该在系统范围内是唯一的。
这种失配并不是不很容易发生,程序可能发现自己正在对象FIFO和kmouse这类非串口输入流修改波特率。
如果每一个ioctl命令都是唯一的,应用程序就会获得一个EINV AL错误,而不是无意间成功地完成了操作。
为了达到唯一性的目的,每一个命令号都应该由多个位字段组成。
Linux的第一版使用了一个16位整数:高8位是与设备相关的“幻”数,低8位是一个序列号码,在设备内是唯一的。
这是因为,用Linus的话说,他有点“无头绪”,后来才接收了一个更好的位字段分割方案。
遗憾的是,很少有驱动程序使用新的约定,这就挫伤了程序员使用新约定的热情。
在我的源码中,为了发掘这种约定都提供了那些功能,同时防止被其他开发人员当成异教徒而禁止,我使用了新的定义命令的方法。
为了给我的驱动程序选择ioctl号,你应该首先看看include/asm/ioctl.h和Documentation/ioctl-number.txt这两个文件。
头文件定义了位字段:类型(幻数),基数,传送方向,参数的尺寸等等。
ioctl-number.txt文件中罗列了在内核中使用的幻数。
这个文件的新版本(2.0以及后继内核)也给出了为什么应该使用这个约定的原因。
很不幸,在1.2.x中发行的头文件没有给出切分ioctl位字段宏的全集。
如果你需要象我的scull一样使用这种新方法,同时还要保持向后兼容性,你使用scull/sysdep.h中的若干代码行,我在那里给出了解决问题的文档的代码。
现在已经不赞成使用的选择ioctl号码的旧方法非常简单:选择一个8位幻数,比如“k”(十六进制为0x6b),然后加上一个基数,就象这样:#define SCULL_IOCTL1 0x6b01#define SCULL_IOCTL2 0x6b02如果应用程序和驱动程序都使用了相同的号码,你只要在驱动程序里实现switch 语句就可以了。
但是,这种在传统Unix中有基础的定义ioctl号码的方法,不应该再在新约定中使用。
这里我介绍就方法只是想给你看看一个ioctl号码大致是个什么样子的。
新的定义号码的方法使用了4个位字段,它们有如下意义。
下面我所介绍的新符号都定义在<linux/ioctl.h>中。
类型幻数。
选择一个号码,并在整个驱动程序中使用这个号码。
这个字段有8位宽(_IOC_TYPEBITS)。
号码基(序列)数。
它也是8位宽(_IOC_NRBITS)。
方向如果该命令有数据传输,它定义数据传输的方向。
可以使用的值有,_IOC_NONE (没有数据传输),_IOC_READ,_IOC_WRITE和_IOC_READ | _IOC_WRITE (双向传输数据)。
数据传输是从应用程序的角度看的;IOC_READ意味着从设备中读数据,驱动程序必须向用户空间写数据。
注意,该字段是一个位屏蔽码,因此可以用逻辑AND操作从中分解出_IOC_READ和_IOC_WRITE。
尺寸所涉及的数据大小。
这个字段的宽度与体系结构有关,当前的范围从8位到14位不等。
你可以在宏_IOC_SIZEBITS中找到某种体系结构的具体数值。
不过,如果你想要你的驱动程序可移植,你只能认为最大尺寸可达255个字节。
系统并不强制你使用这个字段。
如果你需要更大尺度的数据传输,你可以忽略这个字段。
下面我们将介绍如何使用这个字段。
包含在<linux/ioctl.h>之中的头文件<asm/ioctl.h>定义了可以用来构造命令号码的宏:_IO(type,nr),_IOR(type,nr,size),_IOW(type,nr,size)和IOWR(type,nr,size)。
每一个宏都对应一种可能的数据传输方向,其他字段通过参数传递。
头文件还定义了解码宏:_IOC_DIR(nr),_IOC_TYPE(nr),_IOC_NR(nr)和_IOC_SIZE(nr)。
我不打算详细介绍这些宏,头文件里的定义已经足够清楚了,本节稍后会给出样例。
这里是scull中如果定义ioctl命令的。
特别地,这些命令设置并获取驱动程序的配置参数。
在标准的宏定义中,要传送的数据项的尺寸有数据项自身的实例代表,而不是sizeof(item),这是因为sizeof是宏扩展后的一部分。
(代码)最后一条命令,HARDRESET,用来将模块使用计数器复位为0,这样就可以在计数器发生错误时就可以卸载模块了。
实际的源码定义了从IOCHQSET到HARDRESET间的所有命令,但这里没有列出。
我选择用两种方法实现整数参数传递――通过指针和显式数值,尽管根据已有的约定,ioctl应该使用指针完成数据交换。
同样,这两种方法还用于返回整数:通过指针和设置返回值。
如果返回值是正的,这就可以工作;对与任何一个系统调用的返回值,正值是受保护的(如我们在read和write所见到的),而负值则被认为是一个错误值,用其设置用户空间中的errno变量。
“交换”和“移位”操作并不专用于scull设备。
我实现“交换”操作是为了给出“方向”字段的所有可能值,而“移位”操作则将“告知”和“查询”操作组合在一起。
某些时候是需要原子性*测试兼设置这类操作的――特别是当应用程序需要加锁和解锁时。
显式的命令基数没有什么特殊意义。
它只是用来区分命令的。
事实上,由于ioctl 号码的“方向”为会有所不同,你甚至可以在读命令和写命令中使用同一个基数。
我选择除了在声明中使用基数外,其他地方都不使用它,这样我就不必为符号值赋值了。
这也是为什么显式的号码出现在上面的定义中。
我只是向你介绍一种使用命令号码的方法,你可以自由地采用不同的方法使用它。
当前,参数cmd的值内核并没有使用,而且以后也不可能使用。
因此,如果你*当一段程序代码总是被当做一条指令被执行,且不可能在期间发生其他操作,我们就称这段代码是原子性的。
想偷懒,你可以省去上面那些复杂的声明,而直接显式地使用一组16位数值。
但另一方面,如果你这样做了,你就无法从使用位字段中受益了。
头文件<linux/kd.h>就是这种旧风格方法的例子,但是它们并不是因为偷懒才这样做的。
修改这个文件需要重新编译许多应用程序。
返回值ioctl的实现通常就是根据命令号码的一个switch语句。
但是,当命令号码不能匹配任何一个合法操作时,default选择使用是什么?这个问题是很有争议性的。
大多数内核函数返回-EINV AL(“非法参数”),这是由于命令参数确实不是一个合法的参数,这样做是合适的。
然而,POSIX标准上说,如果调用了一个不合适的ioctl命令,应该返回-ENOTTY。
对应的消息是“不是终端”――这不是用户所期望的。
你不得不决定是严格依从标准还是一般常识。
我们将本章的后面介绍为什么依从POSIX标准需要返回ENOTTY。
预定义命令尽管ioctl系统调用大部分都用于操作设备,但还有一些命令是由内核识别的。