linux设备驱动扫盲

Q: 为什么一般要把设备分为“字符设备”和“块设备”?

A:

     一方面, 是为了描述上的方便。像磁盘那样的,以块或扇区为单位,成块进行输入输出的设备,称为块设备;像键盘那样的,以字符(字节)为单位、逐个字符进行输入输出的设备,称为字符设备。文件系统通常都建立在块设备上。

    另一方面,也是更重要的一方面,是为了技术处理上的方便。对于不同的设备,其文件系统层的“厚度”有所不同。第一,对于像磁盘这样结构性很强并且内容需要进一步组织和抽象的设备来说,其文件系统很“厚重”,这是由磁盘设备的复杂性决定的;而对于一些像字符终端这样的字符设备,其文件系统比较薄,设备驱动层也比较简单。第二,与代表着文件的索引结点一样,代表着设备的索引结点中记载着与特定设备建立连接所需的信息。这种信息由三部分组成:文件(包括设备)的类型、主设备号和次设备号。其中设备类型和主设备号合在一起唯一地确定了设备驱动程序,而次设备号则说明目标设备是同类设备中的第几个。例如,当主设备号为2时,若设备类型为块设备就指的软盘驱动器,而若为字符设备则是指所谓“伪终端(pseudo tty)”设备。

     要使一项设备在系统中可见、称为应用程序可以访问的设备,首先要再系统中建立一个代表此设备的设备文件,这是通过系统调用mknode()实现的。除此之外,更重要的是在设备驱动层要有这种设备的驱动程序。设备驱动程序是直接去物理设备打交道的。

 

Q: 什么是设备驱动程序?

A: CPU并不是系统中唯一的智能设备,每个物理设备都有自己的控制器。例如:IDE控制器控制IDE硬盘,SCSI控制器控制SCSI硬盘,等等。每个硬件控制器也有各自的控制状态寄存器(CSR),并且各不相同,这些寄存器用于启动、停止、初始化设备以及对设备故障进行诊断。

      在linux中,管理硬件设备控制器的代码并没有放置在每个应用程序中,而是由内核统一管理,这些处理和管理硬件控制器的软件就是设备驱动程序。 设备驱动程序是内核的一部分。

    设备驱动程序为应用程序屏蔽了硬件细节,应用程序可以像操作普通文件一样对硬件设备进行操作。

                                                                            

     Linux内核的设备管理是由一组运行在特权级上、驻留在内存以及对底层硬件进行处理的共享库的驱动程序来完成的。

 

Q: 为什么说设备驱动程序是文件系统与硬件设备之间的桥梁?

A:  Linux操作系统将所有的设备都看成文件,也就是说,把设备纳入文件系统的范畴来管理。具体来说,有以下三个方面:

第一,每个设备都对应一个文件名,在内核中也就对应一个索引结点。应用程序通过设备的文件名来寻访具体的设备,而设备则像普通文件一样,受到文件系统访问权限控制机制的保护。

第二,对文件操作的系统调用大都适用于设备文件。

第三,从应用程序的角度看,设备文件的逻辑空间是一个线性空间(起始地址为0,每读取一个字节加一)。从这个逻辑空间到设备物理空间(如磁盘的磁道、扇区等)的映射则由内核提供,并被划分为文件操作和设备驱动两个层次。

      可见,对于一个具体的设备而言,文件操作和设备驱动是同一个事物的不同层次。从这种观点出发,概念上可以把一个系统划分为应用程序、文件系统和设备驱动三个层次。

    对于普通文件,即磁盘文件,文件的逻辑空间在文件系统层内按具体文件系统的结构和规则映射到设备的线性逻辑空间,然后在设备驱动层进一步从设备的逻辑空间映射到其物理空间。这样,一共经历了两次映射。或者,反过来说,磁盘设备的物理空间经过两层抽象而成为普通文件的逻辑空间。

     对于设备文件,文件的逻辑空间通常直接等价于设备的逻辑空间,所以在文件系统层不需要映射。它只需要在设备驱动层完成文件逻辑空间(即设备逻辑空间)到设备物理空间的映射即可。

     大多数设备都是中断驱动的,而块设备往往采用DMA方式,所以物理设备的输入输出从本质上说都是异步的。相比之下,文件操作既可以是异步的,也可以是同步的,但多数情况下是异步的。

    显然,设备驱动是文件系统与硬件设备之间的桥梁。

 

Q: 什么是I/O端口?什么是内存映射和I/O映射?什么是I/O接口?

A:   设备驱动程序需要直接访问外设或其接口卡上的物理电路,也就是需要直接与外设寄存器打交道。这些外设寄存器,包括控制寄存器、状态寄存器和数据寄存器,被称为I/O端口。

      通常,根据CPU的不同,访问外设寄存器有两种不同的方式。

      第一种方式是内存映射(memory-mapped)。CPU(如Power PC、m68K等)把这些寄存器看成是内存的一部分,寄存器参与内存统一编址。访问寄存器就通过访问一般的内存指令进行。这种CPU没有专门用于设备I/O的指令。

      第二种方式是I/O映射(I/O-mapped).x86系列CPU把外设的寄存器看成一个独立的地址空间,访问内存的指令不能用来访问这些寄存器,需要对外设寄存器的读写操作设置专用的指令

       通常,cpu把要发给设备的命令写入控制寄存器,并从状态寄存器中读出表示设备内部状态的值,CPU还可以通过读取输入寄存器的内容从设备取得数据,也可以通过向输出寄存器中写入数据而把数据输出到设备。

                                             

        那么什么是I/O接口呢?

 

Q: 什么是基于中断的设备驱动程序?

A: 

       基于中断的设备驱动程序指的是硬件设备在需要服务时,向CPU发一个中断信号,引发中断服务处理程序的执行。相对于查询方式,这种方式大大提高了系统资源的利用率,使内核不必一直等到设备执行完任务后才有事可干,而是在设备工作期间内核就可以转去处理其他事务,直到收到中断请求信号时再回头响应设备。

 

Q: 设备驱动程序一般包含哪几部分?

A: 

        Linux的设备驱动程序与外接的接口可以分为三部分:

(1)驱动程序与内核的接口,由数据结构file_operations来完成;

(2)驱动程序与系统引导的接口,这部分利用驱动程序对设备进行初始化;

(3)驱动程序与设备的接口,这部分描述了驱动程序如何与设备进行交互,这与具体的设备密切相关。

        根据功能,驱动程序的代码可以分为如下几个部分:

       (1)驱动程序的注册与注销;

        (2)设备的打开与释放;

        (3)设备的读和写操作;

        (4)设备的控制操作;

        (5)设备的中断和查询处理。

       其中,上述的2、3、4功能可总结为“服务与I/O请求的子程序”。因此,按照功能划分,设备驱动程序,又可理解为以下三个板块:

     (1)自动配置和初始化子程序,负责检测所要驱动的硬件设备是否存在和是否能正常工作。如果该设备正常,则对这个设备及其相关的设备驱动程序需要的软件状态进行初始化。这部分驱动程序只在初始化时被调用一次。

     (2)服务于I/O请求的子程序,即完成用户进程请求的程序。本部分又称为驱动程序的上半部,调用这部分程序是系统调用的结果。这部分程序在执行时,与调用它的进程属于同一个进程,只是将用户态切换成内核态。它具有进行此系统调用用户程序的运行环境。由此,在这部分可调用sleep函数等与进程运行环境相关的函数。

     (3)中断服务程序。本部分又称为驱动程序的下半部。在Linux系统中,我们并不是直接从中断向量表调用设备驱动程序的中断服务子程序,而是由Linux系统来接收硬件中断,再由系统来调用中断服务子程序。中断可以在任何一个进程运行时产生,因此在中断服务程序被调用时,不能依赖于任何进程的状态,也就不能调用任何与进程运行环境有关的函数。

 

   

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1 Linux驱动与模块 1.1 Linux的模块 驱动程序为了与外设硬件进行交互,必须调用Linux内核提供的内存管理、文件系统等 多种功能函数。而用户态的程序只能通过系统调用来使用有限的内核功能,因此驱动程序在 linux系统中被安排在内核态运行,也即可以访问所有的内核功能。 但是为了把内核通用功能与这些驱动程序区分开来,Linux 通常要求驱动程序作为一个 模块(module)在内核空间运行,并且由内核进行管理。当然,实际上模块并非只能用来编写 驱动程序,模块可以作为任何一个独立的功能块,操作内核函数并通过特定接口向应用程序 提供服务。 1.2 模块的编写要求 模块的代码中,必须加入以下头文件,才能正确地引用模块机制的若干函数: #include <linux/module.h> #include<linux/init.h> 当然,如果编写的模块是驱动程序,则还需要加入与驱动程序相关的内存管理、设备注 册、中断管理等头文件。 模块与通常的应用程序不同,并没有一个main函数,而是一些相互作用的函数的集合。 当然,这些集合中必须有一个首先调用的初始化函数,以及一个退出函数。 初始化函数:在模块加载时被调用,负责申请并初始化模块运行时必须的数据结构,此 后这些结构有可能在模块存续期间一直存在。 退出函数:在模块卸载时被调用,卸载后模块内任何数据结构都不该继续存在,因此退 出函数必须仔细的把模块运行带来的所有数据结构释放掉,否则将会造成内存泄露。 为了使内核知道模块中初始化函数和退出函数的函数名,必须用以下两个宏来定义: module_init(s3c_ts_init); module_exit(s3c_ts_exit); 上例中s3c_ts_init被定义为模块的初始化函数,s3c_ts_exit被定
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值