I/O体系结构和设备驱动程序(一)

来源:互联网 发布:怎么看淘宝抢购前100 编辑:程序博客网 时间:2024/05/29 18:15

1、I/O体系结构

为确保计算机能够正常工作,必须提供数据通路,让信息在连接到计算机的CPU、RAM、和I/O设备之间流动,这些数据通路总称为总线,担当计算机内部主通信通道的作用。

 

所有计算机都拥有一条系统总线,它连接大部分内部硬件设备,一种典型的系统总线是PCI(Peripheral Component Interconnect)总线。目前使用其他类型的总线也很多,例如:ISA、EISA、MCA、SCSI和USB。典型的情况是,一台计算机包括几种不同类型的总线,它们通过被称作"桥"的硬件设备连接在一起。两条高速总线用于在内存芯片上来回传送数据:前端总线将CPU连接到RAM控制器上,而后端总线将CPU连接到外部硬件的高速缓存上。主机上的桥将系统总线和前端总线连接在一起。

 

任何I/O设备有且仅能连接一条总线。总线的类型影响I/O设备的内部设计,也影响着内核如何处理设备。

 

CPU和I/O设备之间的数据通路通常称为I/O总线。80x86微处理器使用16位的地址总线对I/O设备进行寻址,而使用8位、16位或32位数据总线传递数据,每个I/O设备依次连接到I/O总线上,这种连接使用了包含3个元素的硬件组织层次:I/O端口、接口和设备控制器。


1.1、I/O端口

每个连接到I/O总线上的设备都有自己的I/O地址集,通常称为I/O端口,在IBM PC体系结构中,I/O地址空间一共提供了65536个8位的I/O端口,正好对应16位的端口地址。可以把两个连续的8位端口看成一个16位端口,但是这必须从偶数地址开始。同理,也可以把两个连续的16位端口看成一个32位端口,但是这必须是从4的整数倍地址开始。有4条专用的汇编语言指令可以允许CPU对I/O端口进行读写,它们是in、ins、out和outs。在执行其中的一条指令时,CPU使用地址总线选择所请求的I/O端口,使用数据总线在CPU寄存器和端口之间传送数据。

 

I/O端口既可以使用独立的I/O地址空间,也可以被映射到物理地址空间(处理器和I/O设备之间的通信就可以使用对内存直接进行操作的汇编指令,现代的硬件设备更倾向于映射I/O,因为这样处理速度较快,并可以和DMA结合起来)。

 

系统设计者的主要目的是对I/O编程提供统一的方法,但又不能牺牲性能,为达到这个目的,每个设备的I/O端口都被组织成如下图所示的一组专用寄存器,同时为降低成本,通常把同一I/O端口用于不同目的。


访问I/O端口

访问I/O端口的汇编语言指令有:in、out、ins、outs,内核中辅助函数:

l  inb()、 inw()、inl()

分别从I/O端口读取1、2或4个连续字节。

l  inb_p()、inw_p()、inl_p()

分别从I/O端口读取1、2或4个连续字节,然后执行一条”哑元(dummy,即空指令)”指令使CPU暂停。

l  outb()、outw()、outl()

分别向一个I/O端口写入1、2或4个连续字节。

l  outb_p()、outw_p()、outl_p()

分别向一个I/O端口写入1、2或4个连续字节, 然后执行一条”哑元(dummy,即空指令)”指令使CPU暂停。

l  insb()、insw()、insl()

分别从I/O端口读取以1、2或4个字节为一组的连续字节序列,字节序列长度由函数

参数给出。

l  outsb()、outsw()、outsl()

分别向I/O端口写入以1、2或4个字节为一组的连续字节序列,字节序列长度由函数

参数给出。

 

如何知道哪些端口已经分配给I/O设备了呢?

内核必须使用“资源”来记录分配给每个硬件设备的I/O端口。资源(resource)表示某个实体的一部分,这部分被互斥地分配给设备驱动程序,在这里,一个资源表示I/O端口地址的一个范围,每个资源对应的信息放在resource数据结构中。

<linux/ioport.h>

struct resource {    resource_size_t start;      /*资源范围的开始*/    resource_size_t end;       /*资源范围的结束*/    const char *name;         /*资源拥有者的描述*/    unsigned long flags;        /*各种标记*/    /*指向资源树中父亲、兄弟、第一个孩子的指针*/    struct resource *parent, *sibling, *child;};


所有的同种资源都插入到一个树型数据结构中,如表示I/O端口地址范围的所有资源都包含在一个根节点为ioport_resource的树中。节点的孩子被收集到一个链表中,child指向第一个孩子,sibling字段指向链表中的下一个节点。

<kernel/resource.c>

struct resource ioport_resource = {    .name= "PCI IO",    .start= 0,    .end= IO_SPACE_LIMIT,       //与体系结构相关    .flags= IORESOURCE_IO,};

任何设备驱动程序都可以使用下面三个函数,传递给它们的参数为资源树的根节点和要插入的新资源数据结构的地址:

<kernel/resource.c>

int  request_resource(struct resource *root, struct resource *new)

把一个给定范围分配给一个I/O设备

/*** allocate_resource - allocate empty slot in the resource tree given range & alignment* @root: root resource descriptor* @new: resource descriptor desired by caller* @size: requested resource region size* @min: minimum size to allocate* @max: maximum size to allocate* @align: alignment requested, in bytes* @alignf: alignment function, optional, called if not NULL* @alignf_data: arbitrary data to pass to the @alignf function*/int allocate_resource(struct resource *root, struct resource *new,      resource_size_t size, resource_size_t min,      resource_size_t max, resource_size_t align,      void (*alignf)(void *, struct resource *,     resource_size_t, resource_size_t),           void *alignf_data)


在资源树中寻找一个给定大小和排列方式的可用范围;若存在,就将这个范围分配给一个I/O设备(主要由PCI设备驱动程序使用,这种驱动程序可以配置成使用任意的端口号和主板上的内存地址对其进行配置)。

/**

* release_resource - release a previously reserved resource

* @old: resource pointer

*/

int release_resource(struct resource *old)

释放以前分配给I/O设备的给定范围。

 

此外,内核还提供了以上应用于I/O端口的快捷函数:request_region()、release_region()。当前分配给I/O设备的所有I/O地址的树都可以从/proc/ioports文件中获得。

1.2、I/O接口

I/O接口是处于一组I/O端口和对应的设备控制器之间的一种硬件电路。它起翻译器的作用,即把I/O端口中的值转换成设备所需要的命令和数据。在相反方向上,它检测设备状态的变化,并对起状态寄存器作用的I/O端口进行相应的更新。还可以通过一条IRQ线把这种电路连接到可编程中断控制器上,以使它代表相应的设备发出中断请求。

 

有2种类型的接口:

l  专用I/O接口

专门用于一个特定的硬件设备。在一些情况下,设备控制器与这种I/O接口处于同一块卡中,连接到专用I/O接口上的设备及可以是内部设备(PC机箱内),也可以是外部设备(PC机箱外部)。

l  通用I/O接口

用来连接多个不同的硬件设备。连接到通用I/O接口上的设备通常都是外部设备。

1.3、设备控制器

复杂的设备可能需要一个设备控制器来驱动,本质上讲,控制器起2个重要作用:

l  对从I/O接口收到的高级命令进行解释,并通过向设备发送适当的电信号序列强制设备执行特定的操作。

l  对从设备接收到的电信号进行转换和适当的解释,并修改(通过I/O接口)状态寄存器的值。

比较典型的设备控制器,例如磁盘控制器。简单的设备没有设备控制器,如可编程中断控制器和可编程间隔定时器。

 

很多设备都有自己的存储器,通常称之为I/O共享存储器,如比较新的图形卡的帧缓冲区中都有几MB的RAM,用它来存放要在屏幕上显示的屏幕映像。

2、设备驱动程序模型

如今,设备驱动程序设计需要特别的关注:

l  电源管理(控制设备电源线上不同的电压级别)

系统中所有硬件设备由内核全权负责电源管理,注意整个系统中处理电源时,比如”待机”,硬件设备必须按准确的顺序进行操作。

l  即插即用(配置设备时透明的资源分配)

l  热插拔(系统运行时支持设备的插入和移走)

2.1、sysfs文件系统

Sysfs文件系统是一种特殊文件系统,被安装在/sys目录下,sysfs文件系统的目标是展现设备驱动程序模型组件间的层次关系,允许用户态应用程序访问内核内部数据结构的一种文件系统,该文件系统的高层目录是:

block

块设备,独立于所连接的总线

devices

所有被内核识别的硬件设备,依照连接它们的总线对其进行组织

bus

系统中用于连接设备的总线

drivers

在内核中注册的设备驱动程序

class

系统中设备的类型(声卡、网卡、显卡等等);同一类可能包含由不同总线连接的设备,于是由不同的驱动程序驱动。

power

处理一些硬件设备电源状态的文件

firmware

处理一些硬件设备的固件的文件

Sysfs文件系统中所表示的设备驱动程序模型组件之间的关系就像目录和文件之间符号链接的关系一样。

 

Sysfs文件系统中普通文件的主要作用是表示驱动程序和设备的属性。

原创粉丝点击