请教:linux 字符设备驱动IIC进不了中断
如何编写Linux设备驱动程序回想学习Linux操作系统已经有近一年的时间了,前前后后,零零碎碎的一路学习过来,也该试着写的东西了。也算是给自己能留下一点记忆和回忆吧!由于完全是自学的,以下内容若有不当之处,还请大家多指教。Linux是Unix操作系统的一种变种,在Linux下编写驱动程序的原理和思想完全类似于其他的Unix系统,但它dos或window环境下的驱动程序有很大的区别。在Linux环境下设计驱动程序,思想简洁,操作方便,功能也很强大,但是支持函数少,只能依赖kernel中的函数,有些常用的操作要自己来编写,而且调试也不方便。以下的一些文字主要来源于khg,johnsonm的Writelinuxdevicedriver,Brennan’sGuidetoInlineAssembly,TheLinuxA-Z,还有清华BBS上的有关devicedriver的一些资料。一、Linuxdevicedriver的概念 系统调用是操作系统内核和应用程序之间的接口,设备驱动程序是操作系统内核和机器硬件之间的接口。设备驱动程序为应用程序屏蔽了硬件的细节,这样在应用程序看来,硬件设备只是一个设备文件,应用程序可以象操作普通文件一样对硬件设备进行操作。设备驱动程序是内核的一部分,它完成以下的功能: 1、对设备初始化和释放。 2、把数据从内核传送到硬件和从硬件读取数据。 3、读取应用程序传送给设备文件的数据和回送应用程序请求的数据。 4、检测和处理设备出现的错误。 在Linux操作系统下有三类主要的设备文件类型,一是字符设备,二是块设备,三是网络设备。字符设备和块设备的主要区别是:在对字符设备发出读/写请求时,实际的硬件I/O一般就紧接着发生了,块设备则不然,它利用一块系统内存作缓冲区,当用户进程对设备请求能满足用户的要求,就返回请求的数据,如果不能,就调用请求函数来进行实际的I/O操作。块设备是主要针对磁盘等慢速设备设计的,以免耗费过多的CPU时间来等待。 已经提到,用户进程是通过设备文件来与实际的硬件打交道。每个设备文件都都有其文件属性(c/b),表示是字符设备还是块设备?另外每个文件都有两个设备号,第一个是主设备号,标识驱动程序,第二个是从设备号,标识使用同一个设备驱动程序的不同的硬件设备,比如有两个软盘,就可以用从设备号来区分他们。设备文件的的主设备号必须与设备驱动程序在登记时申请的主设备号一致,否则用户进程将无法访问到驱动程序。 最后必须提到的是,在用户进程调用驱动程序时,系统进入核心态,这时不再是抢先式调度。也就是说,系统必须在你的驱动程序的子函数返回后才能进行其他的工作。如果你的驱动程序陷入死循环,不幸的是你只有重新启动机器了,然后就是漫长的fsck。 读/写时,它首先察看缓冲区的内容,如果缓冲区的数据未被处理,则先处理其中的内容。 如何编写Linux操作系统下的设备驱动程序 二、实例剖析我们来写一个最简单的字符设备驱动程序。虽然它什么也不做,但是通过它可以了解Linux的设备驱动程序的工作原理。把下面的C代码输入机器,你就会获得一个真正的设备驱动程序。#define__NO_VERSION__#include#include charkernel_version=UTS_RELEASE; 这一段定义了一些版本信息,虽然用处不是很大,但也必不可少。Johnsonm说所有的驱动程序的开头都要包含,一般来讲最好使用。 由于用户进程是通过设备文件同硬件打交道,对设备文件的操作方式不外乎就是一些系统调用,如open,read,write,close…,注意,不是fopen,fread,但是如何把系统调用和驱动程序关联起来呢?这需要了解一个非常关键的数据结构:structfile_operations{int(*seek)(structinode*,structfile*,off_t,int);int(*read)(structinode*,structfile*,char,int);int(*write)(structinode*,structfile*,off_t,int);int(*readdir)(structinode*,structfile*,structdirent*,int);int(*select)(structinode*,structfile*,int,select_table*);int(*ioctl)(structinode*,structfile*,unsinedint,unsignedlong);int(*mmap)(structinode*,structfile*,structvm_area_struct*);int(*open)(structinode*,structfile*);int(*release)(structinode*,structfile*);int(*fsync)(structinode*,structfile*);int(*fasync)(structinode*,structfile*,int);int(*check_media_change)(structinode*,structfile*);int(*revalidate)(dev_tdev);} 这个结构的每一个成员的名字都对应着一个系统调用。用户进程利用系统调用在对设备文件进行诸如read/write操作时,系统调用通过设备文件的主设备号找到相应的设备驱动程序,然后读取这个数据结构相应的函数指针,接着把控制权交给该函数。这是linux的设备驱动程序工作的基本原理。既然是这样,则编写设备驱动程序的主要工作就是编写子函数,并填充file_operations的各个域。 下面就开始写子程序。#include#include#include#include#include#includeunsignedinttest_major=0;staticintread_test(structinode*node,structfile*file,char*buf,intcount){intleft;if(verify_area(VERIFY_WRITE,buf,count)==-EFAULT)return-EFAULT;for(left=count;left》0;left--){__put_user(1,buf,1);buf++;}returncount;}这个函数是为read调用准备的。当调用read时,read_test()被调用,它把用户的缓冲区全部写1。buf是read调用的一个参数。它是用户进程空间的一个地址。但是在read_test被调用时,系统进入核心态。所以不能使用buf这个地址,必须用__put_user(),这是kernel提供的一个函数,用于向用户传送数据。另外还有很多类似功能的函数。请参考Robert著的《Linux内核设计与实现》(第二版)。然而,在向用户空间拷贝数据之前,必须验证buf是否可用。这就用到函数verify_area。staticintwrite_tibet(structinode*inode,structfile*file,constchar*buf,intcount){returncount;}staticintopen_tibet(structinode*inode,structfile*file){MOD_INC_USE_COUNT;return0;}staticvoidrelease_tibet(structinode*inode,structfile*file){MOD_DEC_USE_COUNT;} 这几个函数都是空操作。实际调用发生时什么也不做,他们仅仅为下面的结构提供函数指针。structfile_operationstest_fops={NULL,read_test,write_test,NULL,/*test_readdir*/NULL,NULL,/*test_ioctl*/NULL,/*test_mmap*/open_test,release_test,NULL,/*test_fsync*/NULL,/*test_fasync*//*nothingmore,fillwithNULLs*/}; 这样,设备驱动程序的主体可以说是写好了。现在要把驱动程序嵌入内核。驱动程序可以按照两种方式编译。一种是编译进kernel,另一种是编译成模块(modules),如果编译进内核的话,会增加内核的大小,还要改动内核的源文件,而且不能动态的卸载,不利于调试,所以推荐使用模块方式。intinit_module(void){intresult;result=register_chrdev(0,“test“,&test_fops);if(result#include#include#includemain(){inttestdev;inti;charbuf;testdev=open(“/dev/test“,O_RDWR);if(testdev==-1){printf(“Cann’topenfile\n“);exit(0);}read(testdev,buf,10);for(i=0;i《10;i++)printf(“%d\n“,buf[i]);close(testdev);} 编译运行,看看是不是打印出全1? 以上只是一个简单的演示。真正实用的驱动程序要复杂的多,要处理如中断,DMA,I/Oport等问题。这些才是真正的难点。请看下节,实际情况的处理。如何编写Linux操作系统下的设备驱动程序 三、设备驱动程序中的一些具体问题 1。I/OPort。 和硬件打交道离不开I/OPort,老的ISA设备经常是占用实际的I/O端口,在linux下,操作系统没有对I/O口屏蔽,也就是说,任何驱动程序都可对任意的I/O口操作,这样就很容易引起混乱。每个驱动程序应该自己避免误用端口。 有两个重要的kernel函数可以保证驱动程序做到这一点。 1)check_region(intio_port,intoff_set) 这个函数察看系统的I/O表,看是否有别的驱动程序占用某一段I/O口。 参数1:I/O端口的基地址, 参数2:I/O端口占用的范围。 返回值:0没有占用,非0,已经被占用。 2)request_region(intio_port,intoff_set,char*devname) 如果这段I/O端口没有被占用,在我们的驱动程序中就可以使用它。在使用之前,必须向系统登记,以防止被其他程序占用。登记后,在/proc/ioports文件中可以看到你登记的I/O口。 参数1:io端口的基地址。 参数2:io端口占用的范围。 参数3:使用这段io地址的设备名。 在对I/O口登记后,就可以放心地用inb(),outb()之类的函来访问了。在一些pci设备中,I/O端口被映射到一段内存中去,要访问这些端口就相当于访问一段内存。经常性的,我们要获得一块内存的物理地址。 2。内存操作 在设备驱动程序中动态开辟内存,不是用malloc,而是kmalloc,或者用get_free_pages直接申请页。释放内存用的是kfree,或free_pages。请注意,kmalloc等函数返回的是物理地址! 注意,kmalloc最大只能开辟128k-16,16个字节是被页描述符结构占用了。 内存映射的I/O口,寄存器或者是硬件设备的RAM(如显存)一般占用F0000000以上的地址空间。在驱动程序中不能直接访问,要通过kernel函数vremap获得重新映射以后的地址。 另外,很多硬件需要一块比较大的连续内存用作DMA传送。这块程序需要一直驻留在内存,不能被交换到文件中去。但是kmalloc最多只能开辟128k的内存。 这可以通过牺牲一些系统内存的方法来解决。 3。中断处理 同处理I/O端口一样,要使用一个中断,必须先向系统登记。intrequest_irq(unsignedintirq,void(*handle)(int,void*,structpt_regs*),unsignedintlongflags,constchar*device);irq:是要申请的中断。handle:中断处理函数指针。flags:SA_INTERRUPT请求一个快速中断,0正常中断。device:设备名。 如果登记成功,返回0,这时在/proc/interrupts文件中可以看你请求的中断。 4。一些常见的问题。对硬件操作,有时时序很重要(关于时序的具体问题就要参考具体的设备芯片手册啦!比如网卡芯片RTL8139)。但是如果用C语言写一些低级的硬件操作的话,gcc往往会对你的程序进行优化,这样时序会发生错误。如果用汇编写呢,gcc同样会对汇编代码进行优化,除非用volatile关键字修饰。最保险的法是禁止优化。这当然只能对一部分你自己编写的代码。如果对所有的代码都不优化,你会发现驱动程序根本无法装载。这是因为在编译驱动程序时要用到gcc的一些扩展特性,而这些扩展特性必须在加了优化选项之后才能体现出来。写在后面:学习Linux确实不是一件容易的事情,因为要付出很多精力,也必须具备很好的C语言基础;但是,学习Linux也是一件非常有趣的事情,它里面包含了许多高手的智慧和“幽默”,这些都需要自己亲自动手才能体会到,O(∩_∩)O~哈哈!
本本win7装linux用VMWARE好还是双系统好,能说详细点么(我是华硕的本,64位,2G内存,320G)
看你装linux的目的了,如果只是装了玩玩就vmware好些,不玩了卸载了就行。装双系统现在也挺方便的,不过卸载起来有点点饭,要删除分区了,合并分区什么的。最主要还是你要拿来干什么,在驱动上,win7不能用的,在虚拟机里面的linux也不能用,win7能用的,虚拟机里面也不一定能用,受限于wn7。装双系统要功能全些,效率更高些
linux操作系统怎么安装
一、安装前的准备 Linux安装光盘支持由光驱启动安装,用户只要对BIOS进行相应设置,就可以由光盘直接启动进入Linux的安装界面。在正式安装Linux操作系统之前,用户应注意以下两个方面的问题: 1.硬盘空间 Linux需要在硬盘上建立自己的磁盘分区,如果用户不希望对现有系统下的硬盘进行重新分区,建议使用一些第三方工具软件,如Partition Magic等,对硬盘上已经存在的分区进行压缩,从而为安装Linux腾出足够空间。用户需要为Linux预留大约500兆硬盘空间,既可以位于已经存在的扩展分区,也可以是没有被划分分区的硬盘空间。Red Hat Linux 6.0可以在安装过程中自己创建分区,所以用户所要做的只是为Linux操作系统预留足够的硬盘空间即可。 2.记录用户机器硬件配置信息 虽然Linux的安装过程已经被尽可能的简化,但是Linux仍然有可能不能自动检测到用户系统中的所有硬件配置。用户在安装过程中可能要回答某些硬件的设置问题,为了保证安装的系统可用,好用,建议用户在安装之前记录下系统的硬件配置信息。一个最简单的方法是在Windows下用鼠标右击“我的电脑”,选中“属性”,在出现的对话框中点击“设备管理”。其中包含了用户需要知道的所有信息,用户尤其应当注意显示器、显卡和声卡的配置情况。 二、开始安装 注意,在启动Linux的安装过程之后,没有类似Windows系统安装中“退出安装”的功能选项。如果用户在安装过程中碰到无法解决的问题而不能继续进行安装时,可以同时按下“Ctrl+Alt+Delete”键退出安装过程,等到找到问题的解决方法之后重新进行安装。 Red Hat Linux的安装过程采用图形界面,由键盘进行控制。其中“Tab”键用于在不同的选项之间移动,空格键用于选定或取消对某一项的选择,“Enter”键用于按动屏幕中高亮度突出显示的按钮。在屏幕的底部显示可能会用到的键盘命令。 1.启动安装过程 安装过程一开始,首先出现欢迎对话框,用户按“Enter”键继续。Red Hat先会询问用户使用何种语言、用户使用的键盘类型(默认选项为美式键盘”)以及安装软件的位置(选择“本地CD-ROM)。在随后的升级或安装系统的询问中选择“安装”,使用何种安装类型选择“自定义安装”。 Red Hat在用户对上述问题作出答复之后,检测用户系统中是否存在SCSI 设备。如果Linux自己没有找到任何的SCSI 设备,就会询问用户是否使用了SCSI 设备。大多数用户可以回答“否”,如果用户确实使用了SCSI 设备,就要在列出的SCSI 设备驱动中进行选择,并提供一些基本的配置参数以便使Linux系统能够正常使用该设备。 2.使用Disk Druid建立Linux文件系统 在第1个过程结束之后,Red Hat将会提示用户建立Linux文件系统。在被询问使用何种工具时,选择Disk Druid。(见^22020305a^1) 现在用户需要在预留的硬盘空间中创建两个分区。第一个分区作为Linux的根(root)分区,用于安装Linux文件。第二个分区作为交换分区,用于补充用户的物理内存。该分区相当于Windows 系统中的交换文件,但是Linux需要建立一个独立的交换分区。在硬盘预留空间添加分区的方法如下: 按“F1”键添加分区,输入“/”作为安装点(mount point),选择Linux Native(Linux本地分区)作为分区类型,然后在设定完分区大小之后按“OK”完成分区添加过程。 用户可以按照同样的步骤添加一个交换分区。注意“安装点”一项空出,选择“Linux Swap”作为分区类型,交换分区的大小不能低于用户物理内存的实际大小。例如,如果用户内存为36MB,交换分区的大小至少应当为36MB。 Disk Druid将会显示出用户添加的两个分区的信息:一个较大的根分区和一个较小的交换分区。用户选择“OK”,当Red Hat询问用户是否将所做的改动保存到分区表时回答“是”。这样就完成了整个分区的添加过程。 在添加完分区之后,用户需要对新分区进行格式化。Red Hat首先格式化交换分区,然后再格式化根分区。建议用户在格式化过程中选择“检查损坏的区块”选项。 3.安装可选软件包 用户可能已经发现在Red Hat Linux光盘中,除了核心操作系统之外,还含有大量功能强大的实用软件。如图像处理功能可以与Photoshop媲美的Gimp,使用广泛的Web服务器Apache等。Linux的安装程序规定了一组默认安装的软件,包括E-mail客户端软件、Telnet、 FTP 以及Web浏览器等。但是在默认情况下将不安装打印机支持程序和DOS/Windows 连接程序。用户可以根据自己的需要选择安装哪些软件。(见^22020305b^2) 下面对Linux的X Window系统做一个简单介绍。X Window系统为用户提供了Linux系统下类似于Windows系统的图形化用户界面。但是与Windows不同,X Window支持多个接口,其中包括最著名的GNOME和KDE。X Window并不直接决定用户的桌面环境,而是由X Window的一个部件窗口管理器进行控制。目前流行的窗口管理器有几十种之多,其中一些采用类似Win 95/98 的用户接口,而另外一些则模仿Mac系统的用户接口。GNOME和KDE都属于桌面环境,在窗口管理器之上提供一系列方便用户使用Linux系统的工具和应用程序。 这里笔者对X Window系统进行介绍的目的是希望用户理解。如果需要在Linux系统中使用图形界面,就应当确保在系统的安装过程中选择安装了所有必需的X Window软件包,包括GNOME和KDE。GNOME 有可能已经被设定为默认安装软件,用户只有通过手动选择安装KDE。 一旦用户选择了需要安装的所有软件包,点击“OK”,然后Red Hat 就会告诉用户将要创建安装记录,再次选择“OK”之后,安装程序开始将用户选定的软件复制到硬盘上。当复制过程中出现黑屏时,用户大可不必紧张,因为这是安装程序启动了自带的屏幕保护程序。用户可以通过点击任何一个键盘键回到安装界面。 接下我要在笔记本上安装如下操作系统1、Vista Home Basic2、ubuntu linux 8.043、fedora 94、Red Hat Enterprise Linux 5应该按照怎样的顺序安装呢,最好要在GRUB的启动菜单选择想要启动的操作系统。安装过程中应该注意什么问题呢