⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 00000002.htm

📁 一份很好的linux入门资料
💻 HTM
📖 第 1 页 / 共 2 页
字号:
(4)&nbsp;readdir,取得下一个目录入口点,只有与文件系统相关的设备驱动程序&nbsp;<BR>才使用。&nbsp;<BR>(5)&nbsp;selec,进行选择操作,如果驱动程序没有提供select入口,select操&nbsp;<BR>作将会认为设备已经准备好进行任何的I/O操作。&nbsp;<BR>(6)&nbsp;ioctl,进行读、写以外的其它操作,参数cmd为自定义的的命令。&nbsp;<BR>(7)&nbsp;mmap,用于把设备的内容映射到地址空间,一般只有块设备驱动程序使&nbsp;<BR>用。&nbsp;<BR>(8)&nbsp;open,打开设备准备进行I/O操作。返回0表示打开成功,返回负数表&nbsp;<BR>示失败。如果驱动程序没有提供open入口,则只要/dev/driver文件存&nbsp;<BR>在就认为打开成功。&nbsp;<BR>(9)&nbsp;release,即close操作。&nbsp;<BR>设备驱动程序所提供的入口点,在设备驱动程序初始化的时候向系统进行登&nbsp;<BR>记,以便系统在适当的时候调用。LINUX系统里,通过调用register_chrdev&nbsp;<BR>向系统注册字符型设备驱动程序。register_chrdev定义为:&nbsp;<BR>&nbsp;#include&nbsp;&lt;linux/fs.h&gt;&nbsp;<BR>&nbsp;#include&nbsp;&lt;linux/errno.h&gt;&nbsp;<BR>&nbsp;int&nbsp;register_chrdev(unsigned&nbsp;int&nbsp;major,&nbsp;const&nbsp;char&nbsp;*name,&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;file_operations&nbsp;*fops);&nbsp;<BR>其中,major是为设备驱动程序向系统申请的主设备号,如果为0则系统为此&nbsp;<BR>驱动程序动态地分配一个主设备号。name是设备名。fops就是前面所说的对各个&nbsp;<BR>调用的入口点的说明。此函数返回0表示成功。返回-EINVAL表示申请的主设备号&nbsp;<BR>非法,一般来说是主设备号大于系统所允许的最大设备号。返回-EBUSY表示所申&nbsp;<BR>请的主设备号正在被其它设备驱动程序使用。如果是动态分配主设备号成功,此&nbsp;<BR>函数将返回所分配的主设备号。如果register_chrdev操作成功,设备名就会出&nbsp;<BR>现在/proc/devices文件里。&nbsp;<BR>初始化部分一般还负责给设备驱动程序申请系统资源,包括内存、中断、时&nbsp;<BR>钟、I/O端口等,这些资源也可以在open子程序或别的地方申请。在这些资源不&nbsp;<BR>用的时候,应该释放它们,以利于资源的共享。&nbsp;<BR>在UNIX系统里,对中断的处理是属于系统核心的部分,因此如果设备与系&nbsp;<BR>统之间以中断方式进行数据交换的话,就必须把该设备的驱动程序作为系统核心&nbsp;<BR>的一部分。设备驱动程序通过调用request_irq函数来申请中断,通过free_irq&nbsp;<BR>来释放中断。它们的定义为:&nbsp;<BR>#include&nbsp;&lt;linux/sched.h&gt;&nbsp;<BR>int&nbsp;request_irq(unsigned&nbsp;int&nbsp;irq,&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;(*handler)(int&nbsp;irq,void&nbsp;dev_id,struct&nbsp;pt_regs&nbsp;*regs),&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;long&nbsp;flags,&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;char&nbsp;*device,&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;*dev_id);&nbsp;<BR>void&nbsp;free_irq(unsigned&nbsp;int&nbsp;irq,&nbsp;void&nbsp;*dev_id);&nbsp;<BR>参数irq表示所要申请的硬件中断号。handler为向系统登记的中断处理子&nbsp;<BR>程序,中断产生时由系统来调用,调用时所带参数irq为中断号,dev_id为申&nbsp;<BR>请时告诉系统的设备标识,regs为中断发生时寄存器内容。device为设备名,&nbsp;<BR>将会出现在/proc/interrupts文件里。flag是申请时的选项,它决定中断处理&nbsp;<BR>程序的一些特性,其中最重要的是中断处理程序是快速处理程序(flag里设置&nbsp;<BR>了SA_INTERRUPT)还是慢速处理程序(不设置SA_INTERRUPT),快速处理程序&nbsp;<BR>运行时,所有中断都被屏蔽,而慢速处理程序运行时,除了正在处理的中断外,&nbsp;<BR>其它中断都没有被屏蔽。在LINUX系统中,中断可以被不同的中断处理程序共享,&nbsp;<BR>这要求每一个共享此中断的处理程序在申请中断时在flags里设置SA_SHIRQ,&nbsp;<BR>这些处理程序之间以dev_id来区分。如果中断由某个处理程序独占,则dev_id&nbsp;<BR>可以为NULL。request_irq返回0表示成功,返回-INVAL表示irq&gt;15或&nbsp;<BR>handler==NULL,返回-EBUSY表示中断已经被占用且不能共享。&nbsp;<BR>作为系统核心的一部分,设备驱动程序在申请和释放内存时不是调用malloc&nbsp;<BR>和free,而代之以调用kmalloc和kfree,它们被定义为:&nbsp;<BR>#include&nbsp;&lt;linux/kernel.h&gt;&nbsp;<BR>void&nbsp;*&nbsp;kmalloc(unsigned&nbsp;int&nbsp;len,&nbsp;int&nbsp;priority);&nbsp;<BR>void&nbsp;kfree(void&nbsp;*&nbsp;obj);&nbsp;<BR>参数len为希望申请的字节数,obj为要释放的内存指针。priority为分配内存操&nbsp;<BR>作的优先级,即在没有足够空闲内存时如何操作,一般用GFP_KERNEL。&nbsp;<BR>与中断和内存不同,使用一个没有申请的I/O端口不会使CPU产生异常,也&nbsp;<BR>就不会导致诸如“segmentation&nbsp;fault&quot;一类的错误发生。任何进程都可以访问&nbsp;<BR>任何一个I/O端口。此时系统无法保证对I/O端口的操作不会发生冲突,甚至会&nbsp;<BR>因此而使系统崩溃。因此,在使用I/O端口前,也应该检查此I/O端口是否已有&nbsp;<BR>别的程序在使用,若没有,再把此端口标记为正在使用,在使用完以后释放它。&nbsp;<BR>这样需要用到如下几个函数:&nbsp;<BR>int&nbsp;check_region(unsigned&nbsp;int&nbsp;from,&nbsp;unsigned&nbsp;int&nbsp;extent);&nbsp;<BR>void&nbsp;request_region(unsigned&nbsp;int&nbsp;from,&nbsp;unsigned&nbsp;int&nbsp;extent,&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;char&nbsp;*name);&nbsp;<BR>void&nbsp;release_region(unsigned&nbsp;int&nbsp;from,&nbsp;unsigned&nbsp;int&nbsp;extent);&nbsp;<BR>调用这些函数时的参数为:from表示所申请的I/O端口的起始地址;&nbsp;<BR>extent为所要申请的从from开始的端口数;name为设备名,将会出现在&nbsp;<BR>/proc/ioports文件里。check_region返回0表示I/O端口空闲,否则为正在&nbsp;<BR>被使用。&nbsp;<BR>在申请了I/O端口之后,就可以如下几个函数来访问I/O端口:&nbsp;<BR>#include&nbsp;&lt;asm/io.h&gt;&nbsp;<BR>inline&nbsp;unsigned&nbsp;int&nbsp;inb(unsigned&nbsp;short&nbsp;port);&nbsp;<BR>inline&nbsp;unsigned&nbsp;int&nbsp;inb_p(unsigned&nbsp;short&nbsp;port);&nbsp;<BR>inline&nbsp;void&nbsp;outb(char&nbsp;value,&nbsp;unsigned&nbsp;short&nbsp;port);&nbsp;<BR>inline&nbsp;void&nbsp;outb_p(char&nbsp;value,&nbsp;unsigned&nbsp;short&nbsp;port);&nbsp;<BR>其中inb_p和outb_p插入了一定的延时以适应某些慢的I/O端口。&nbsp;<BR>在设备驱动程序里,一般都需要用到计时机制。在LINUX系统中,时钟是由&nbsp;<BR>系统接管,设备驱动程序可以向系统申请时钟。与时钟有关的系统调用有:&nbsp;<BR>#include&nbsp;&lt;asm/param.h&gt;&nbsp;<BR>#include&nbsp;&lt;linux/timer.h&gt;&nbsp;<BR>void&nbsp;add_timer(struct&nbsp;timer_list&nbsp;*&nbsp;timer);&nbsp;<BR>int&nbsp;&nbsp;del_timer(struct&nbsp;timer_list&nbsp;*&nbsp;timer);&nbsp;<BR>inline&nbsp;void&nbsp;init_timer(struct&nbsp;timer_list&nbsp;*&nbsp;timer);&nbsp;<BR>struct&nbsp;timer_list的定义为:&nbsp;<BR>struct&nbsp;timer_list&nbsp;{&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;timer_list&nbsp;*next;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;timer_list&nbsp;*prev;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;long&nbsp;expires;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;long&nbsp;data;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;(*function)(unsigned&nbsp;long&nbsp;d);&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};&nbsp;<BR>其中expires是要执行function的时间。系统核心有一个全局变量JIFFIES&nbsp;<BR>表示当前时间,一般在调用add_timer时jiffies=JIFFIES+num,表示在num个&nbsp;<BR>系统最小时间间隔后执行function。系统最小时间间隔与所用的硬件平台有关,&nbsp;<BR>在核心里定义了常数HZ表示一秒内最小时间间隔的数目,则num*HZ表示num&nbsp;<BR>秒。系统计时到预定时间就调用function,并把此子程序从定时队列里删除,&nbsp;<BR>因此如果想要每隔一定时间间隔执行一次的话,就必须在function里再一次调&nbsp;<BR>用add_timer。function的参数d即为timer里面的data项。&nbsp;<BR>在设备驱动程序里,还可能会用到如下的一些系统函数:&nbsp;<BR>#include&nbsp;&lt;asm/system.h&gt;&nbsp;<BR>#define&nbsp;cli()&nbsp;__asm__&nbsp;__volatile__&nbsp;(&quot;cli&quot;::)&nbsp;<BR>#define&nbsp;sti()&nbsp;__asm__&nbsp;__volatile__&nbsp;(&quot;sti&quot;::)&nbsp;<BR>这两个函数负责打开和关闭中断允许。&nbsp;<BR>#include&nbsp;&lt;asm/segment.h&gt;&nbsp;<BR>void&nbsp;memcpy_fromfs(void&nbsp;*&nbsp;to,const&nbsp;void&nbsp;*&nbsp;from,unsigned&nbsp;long&nbsp;n);&nbsp;<BR>void&nbsp;memcpy_tofs(void&nbsp;*&nbsp;to,const&nbsp;void&nbsp;*&nbsp;from,unsigned&nbsp;long&nbsp;n);&nbsp;<BR>在用户程序调用read&nbsp;、write时,因为进程的运行状态由用户态变为核心&nbsp;<BR>态,地址空间也变为核心地址空间。而read、write中参数buf是指向用户程&nbsp;<BR>序的私有地址空间的,所以不能直接访问,必须通过上述两个系统函数来访问用&nbsp;<BR>户程序的私有地址空间。memcpy_fromfs由用户程序地址空间往核心地址空间&nbsp;<BR>复制,memcpy_tofs则反之。参数to为复制的目的指针,from为源指针,n&nbsp;<BR>为要复制的字节数。&nbsp;<BR>在设备驱动程序里,可以调用printk来打印一些调试信息,用法与printf&nbsp;<BR>类似。printk打印的信息不仅出现在屏幕上,同时还记录在文件syslog里。&nbsp;<BR>&nbsp;<BR>3.3、LINUX系统下的具体实现&nbsp;<BR>在LINUX里,除了直接修改系统核心的源代码,把设备驱动程序加进核心里&nbsp;<BR>以外,还可以把设备驱动程序作为可加载的模块,由系统管理员动态地加载它,&nbsp;<BR>使之成为核心地一部分。也可以由系统管理员把已加载地模块动态地卸载下来。&nbsp;<BR>LINUX中,模块可以用C语言编写,用gcc编译成目标文件(不进行链接,作&nbsp;<BR>为*.o文件存在),为此需要在gcc命令行里加上-c的参数。在编译时,还应该在&nbsp;<BR>gcc的命令行里加上这样的参数:-D__KERNEL__&nbsp;-DMODULE。由于在不链接时,g&nbsp;<BR>cc只允许一个输入文件,因此一个模块的所有部分都必须在一个文件里实现。&nbsp;<BR>编译好的模块*.o放在/lib/modules/xxxx/misc下(xxxx表示核心版本,如&nbsp;<BR>在核心版本为2.0.30时应该为/lib/modules/2.0.30/misc),然后用depmod&nbsp;-a&nbsp;<BR>使此模块成为可加载模块。模块用insmod命令加载,用rmmod命令来卸载,并可&nbsp;<BR>以用lsmod命令来查看所有已加载的模块的状态。&nbsp;<BR>编写模块程序的时候,必须提供两个函数,一个是int&nbsp;init_module(void),&nbsp;<BR>供insmod在加载此模块的时候自动调用,负责进行设备驱动程序的初始化工作。&nbsp;<BR>init_module返回0以表示初始化成功,返回负数表示失败。另一个函数是void&nbsp;<BR>cleanup_module&nbsp;(void),在模块被卸载时调用,负责进行设备驱动程序的清除&nbsp;<BR>工作。&nbsp;<BR>在成功的向系统注册了设备驱动程序后(调用register_chrdev成功后),&nbsp;<BR>就可以用mknod命令来把设备映射为一个特别文件,其它程序使用这个设备的时&nbsp;<BR>候,只要对此特别文件进行操作就行了。&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>附录:参考文献&nbsp;<BR>&nbsp;<BR>1、&nbsp;《UNIX操作系统设计与实现》&nbsp;<BR>&nbsp;陈华瑛、李建国主编&nbsp;<BR>&nbsp;电子工业出版社出版&nbsp;<BR>2、&nbsp;&nbsp;《Linux&nbsp;Kernel&nbsp;Hacker's&nbsp;Guide》&nbsp;<BR>&nbsp;作者:Michael&nbsp;K.&nbsp;Johnson&nbsp;<BR>3、&nbsp;《Kernel&nbsp;Jorn》&nbsp;<BR>&nbsp;作者:Alessandro&nbsp;Rubini&nbsp;&amp;&nbsp;Georg&nbsp;Zezchwitz&nbsp;<BR>&nbsp;连载于《Linux&nbsp;Journal》1996年36期&nbsp;<BR>4、&nbsp;Linux核心源代码(核心版本2.0.30)&nbsp;<BR>5、&nbsp;Linux-HOWTO&nbsp;<BR>&nbsp;<BR>--&nbsp;<BR>&nbsp;<BR>沧海一声笑&nbsp;<BR>滔滔两岸潮&nbsp;<BR>浮沉随浪只记今朝&nbsp;<BR>来!共进一杯&nbsp;<BR>让我们歌〖笑傲江湖〗到通宵!!!&nbsp;<BR>&nbsp;<BR>※&nbsp;来源:·BBS&nbsp;水木清华站&nbsp;bbs.net.tsinghua.edu.cn·[FROM:&nbsp;ie0.ie.ac.cn]&nbsp;<BR><CENTER><H1>BBS水木清华站∶精华区</H1></CENTER></BODY></HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -